📄 b.xs
字号:
/* B.xs * * Copyright (c) 1996 Malcolm Beattie * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. * */#define PERL_NO_GET_CONTEXT#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#ifdef PERL_OBJECT#undef PL_op_name#undef PL_opargs #undef PL_op_desc#define PL_op_name (get_op_names())#define PL_opargs (get_opargs())#define PL_op_desc (get_op_descs())#endif#ifdef PerlIOtypedef PerlIO * InputStream;#elsetypedef FILE * InputStream;#endifstatic char *svclassnames[] = { "B::NULL", "B::IV", "B::NV", "B::RV", "B::PV", "B::PVIV", "B::PVNV", "B::PVMG", "B::BM", "B::PVLV", "B::AV", "B::HV", "B::CV", "B::GV", "B::FM", "B::IO",};typedef enum { OPc_NULL, /* 0 */ OPc_BASEOP, /* 1 */ OPc_UNOP, /* 2 */ OPc_BINOP, /* 3 */ OPc_LOGOP, /* 4 */ OPc_LISTOP, /* 5 */ OPc_PMOP, /* 6 */ OPc_SVOP, /* 7 */ OPc_PADOP, /* 8 */ OPc_PVOP, /* 9 */ OPc_CVOP, /* 10 */ OPc_LOOP, /* 11 */ OPc_COP /* 12 */} opclass;static char *opclassnames[] = { "B::NULL", "B::OP", "B::UNOP", "B::BINOP", "B::LOGOP", "B::LISTOP", "B::PMOP", "B::SVOP", "B::PADOP", "B::PVOP", "B::CVOP", "B::LOOP", "B::COP" };static int walkoptree_debug = 0; /* Flag for walkoptree debug hook */static SV *specialsv_list[6];static opclasscc_opclass(pTHX_ OP *o){ if (!o) return OPc_NULL; if (o->op_type == 0) return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP; if (o->op_type == OP_SASSIGN) return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);#ifdef USE_ITHREADS if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST) return OPc_PADOP;#endif switch (PL_opargs[o->op_type] & OA_CLASS_MASK) { case OA_BASEOP: return OPc_BASEOP; case OA_UNOP: return OPc_UNOP; case OA_BINOP: return OPc_BINOP; case OA_LOGOP: return OPc_LOGOP; case OA_LISTOP: return OPc_LISTOP; case OA_PMOP: return OPc_PMOP; case OA_SVOP: return OPc_SVOP; case OA_PADOP: return OPc_PADOP; case OA_PVOP_OR_SVOP: /* * Character translations (tr///) are usually a PVOP, keeping a * pointer to a table of shorts used to look up translations. * Under utf8, however, a simple table isn't practical; instead, * the OP is an SVOP, and the SV is a reference to a swash * (i.e., an RV pointing to an HV). */ return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF)) ? OPc_SVOP : OPc_PVOP; case OA_LOOP: return OPc_LOOP; case OA_COP: return OPc_COP; case OA_BASEOP_OR_UNOP: /* * UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on * whether parens were seen. perly.y uses OPf_SPECIAL to * signal whether a BASEOP had empty parens or none. * Some other UNOPs are created later, though, so the best * test is OPf_KIDS, which is set in newUNOP. */ return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP; case OA_FILESTATOP: /* * The file stat OPs are created via UNI(OP_foo) in toke.c but use * the OPf_REF flag to distinguish between OP types instead of the * usual OPf_SPECIAL flag. As usual, if OPf_KIDS is set, then we * return OPc_UNOP so that walkoptree can find our children. If * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set * (no argument to the operator) it's an OP; with OPf_REF set it's * an SVOP (and op_sv is the GV for the filehandle argument). */ return ((o->op_flags & OPf_KIDS) ? OPc_UNOP :#ifdef USE_ITHREADS (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP);#else (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP);#endif case OA_LOOPEXOP: /* * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a * label was omitted (in which case it's a BASEOP) or else a term was * seen. In this last case, all except goto are definitely PVOP but * goto is either a PVOP (with an ordinary constant label), an UNOP * with OPf_STACKED (with a non-constant non-sub) or an UNOP for * OP_REFGEN (with goto &sub) in which case OPf_STACKED also seems to * get set. */ if (o->op_flags & OPf_STACKED) return OPc_UNOP; else if (o->op_flags & OPf_SPECIAL) return OPc_BASEOP; else return OPc_PVOP; } warn("can't determine class of operator %s, assuming BASEOP\n", PL_op_name[o->op_type]); return OPc_BASEOP;}static char *cc_opclassname(pTHX_ OP *o){ return opclassnames[cc_opclass(aTHX_ o)];}static SV *make_sv_object(pTHX_ SV *arg, SV *sv){ char *type = 0; IV iv; for (iv = 0; iv < sizeof(specialsv_list)/sizeof(SV*); iv++) { if (sv == specialsv_list[iv]) { type = "B::SPECIAL"; break; } } if (!type) { type = svclassnames[SvTYPE(sv)]; iv = PTR2IV(sv); } sv_setiv(newSVrv(arg, type), iv); return arg;}static SV *make_mg_object(pTHX_ SV *arg, MAGIC *mg){ sv_setiv(newSVrv(arg, "B::MAGIC"), PTR2IV(mg)); return arg;}static SV *cstring(pTHX_ SV *sv){ SV *sstr = newSVpvn("", 0); STRLEN len; char *s; if (!SvOK(sv)) sv_setpvn(sstr, "0", 1); else { /* XXX Optimise? */ s = SvPV(sv, len); sv_catpv(sstr, "\""); for (; len; len--, s++) { /* At least try a little for readability */ if (*s == '"') sv_catpv(sstr, "\\\""); else if (*s == '\\') sv_catpv(sstr, "\\\\"); else if (*s >= ' ' && *s < 127) /* XXX not portable */ sv_catpvn(sstr, s, 1); else if (*s == '\n') sv_catpv(sstr, "\\n"); else if (*s == '\r') sv_catpv(sstr, "\\r"); else if (*s == '\t') sv_catpv(sstr, "\\t"); else if (*s == '\a') sv_catpv(sstr, "\\a"); else if (*s == '\b') sv_catpv(sstr, "\\b"); else if (*s == '\f') sv_catpv(sstr, "\\f"); else if (*s == '\v') sv_catpv(sstr, "\\v"); else { /* no trigraph support */ char escbuff[5]; /* to fit backslash, 3 octals + trailing \0 */ /* Don't want promotion of a signed -1 char in sprintf args */ unsigned char c = (unsigned char) *s; sprintf(escbuff, "\\%03o", c); sv_catpv(sstr, escbuff); } /* XXX Add line breaks if string is long */ } sv_catpv(sstr, "\""); } return sstr;}static SV *cchar(pTHX_ SV *sv){ SV *sstr = newSVpvn("'", 1); STRLEN n_a; char *s = SvPV(sv, n_a); if (*s == '\'') sv_catpv(sstr, "\\'"); else if (*s == '\\') sv_catpv(sstr, "\\\\"); else if (*s >= ' ' && *s < 127) /* XXX not portable */ sv_catpvn(sstr, s, 1); else if (*s == '\n') sv_catpv(sstr, "\\n"); else if (*s == '\r') sv_catpv(sstr, "\\r"); else if (*s == '\t') sv_catpv(sstr, "\\t"); else if (*s == '\a') sv_catpv(sstr, "\\a"); else if (*s == '\b') sv_catpv(sstr, "\\b"); else if (*s == '\f') sv_catpv(sstr, "\\f"); else if (*s == '\v') sv_catpv(sstr, "\\v"); else { /* no trigraph support */ char escbuff[5]; /* to fit backslash, 3 octals + trailing \0 */ /* Don't want promotion of a signed -1 char in sprintf args */ unsigned char c = (unsigned char) *s; sprintf(escbuff, "\\%03o", c); sv_catpv(sstr, escbuff); } sv_catpv(sstr, "'"); return sstr;}voidwalkoptree(pTHX_ SV *opsv, char *method){ dSP; OP *o; if (!SvROK(opsv)) croak("opsv is not a reference"); opsv = sv_mortalcopy(opsv); o = INT2PTR(OP*,SvIV((SV*)SvRV(opsv))); if (walkoptree_debug) { PUSHMARK(sp); XPUSHs(opsv); PUTBACK; perl_call_method("walkoptree_debug", G_DISCARD); } PUSHMARK(sp); XPUSHs(opsv); PUTBACK; perl_call_method(method, G_DISCARD); if (o && (o->op_flags & OPf_KIDS)) { OP *kid; for (kid = ((UNOP*)o)->op_first; kid; kid = kid->op_sibling) { /* Use the same opsv. Rely on methods not to mess it up. */ sv_setiv(newSVrv(opsv, cc_opclassname(aTHX_ kid)), PTR2IV(kid)); walkoptree(aTHX_ opsv, method); } }}typedef OP *B__OP;typedef UNOP *B__UNOP;typedef BINOP *B__BINOP;typedef LOGOP *B__LOGOP;typedef LISTOP *B__LISTOP;typedef PMOP *B__PMOP;typedef SVOP *B__SVOP;typedef PADOP *B__PADOP;typedef PVOP *B__PVOP;typedef LOOP *B__LOOP;typedef COP *B__COP;typedef SV *B__SV;typedef SV *B__IV;typedef SV *B__PV;typedef SV *B__NV;typedef SV *B__PVMG;typedef SV *B__PVLV;typedef SV *B__BM;typedef SV *B__RV;typedef AV *B__AV;typedef HV *B__HV;typedef CV *B__CV;typedef GV *B__GV;typedef IO *B__IO;typedef MAGIC *B__MAGIC;MODULE = B PACKAGE = B PREFIX = B_PROTOTYPES: DISABLEBOOT:{ HV *stash = gv_stashpvn("B", 1, TRUE); AV *export_ok = perl_get_av("B::EXPORT_OK",TRUE); specialsv_list[0] = Nullsv; specialsv_list[1] = &PL_sv_undef; specialsv_list[2] = &PL_sv_yes; specialsv_list[3] = &PL_sv_no; specialsv_list[4] = pWARN_ALL; specialsv_list[5] = pWARN_NONE;#include "defsubs.h"}#define B_main_cv() PL_main_cv#define B_init_av() PL_initav#define B_begin_av() PL_beginav_save#define B_end_av() PL_endav#define B_main_root() PL_main_root#define B_main_start() PL_main_start#define B_amagic_generation() PL_amagic_generation#define B_comppadlist() (PL_main_cv ? CvPADLIST(PL_main_cv) : CvPADLIST(PL_compcv))#define B_sv_undef() &PL_sv_undef#define B_sv_yes() &PL_sv_yes#define B_sv_no() &PL_sv_noB::AVB_init_av()B::AVB_begin_av()B::AVB_end_av()B::CVB_main_cv()B::OPB_main_root()B::OPB_main_start()long B_amagic_generation()B::AVB_comppadlist()B::SVB_sv_undef()B::SVB_sv_yes()B::SVB_sv_no()MODULE = B PACKAGE = Bvoidwalkoptree(opsv, method) SV * opsv char * method CODE: walkoptree(aTHX_ opsv, method);intwalkoptree_debug(...) CODE: RETVAL = walkoptree_debug; if (items > 0 && SvTRUE(ST(1))) walkoptree_debug = 1; OUTPUT: RETVAL#define address(sv) PTR2IV(sv)IVaddress(sv) SV * svB::SVsvref_2object(sv) SV * sv CODE: if (!SvROK(sv)) croak("argument is not a reference"); RETVAL = (SV*)SvRV(sv); OUTPUT: RETVAL voidopnumber(name)char * nameCODE:{ int i; IV result = -1; ST(0) = sv_newmortal(); if (strncmp(name,"pp_",3) == 0) name += 3; for (i = 0; i < PL_maxo; i++) { if (strcmp(name, PL_op_name[i]) == 0) { result = i; break; } } sv_setiv(ST(0),result);}voidppname(opnum) int opnum CODE: ST(0) = sv_newmortal(); if (opnum >= 0 && opnum < PL_maxo) { sv_setpvn(ST(0), "pp_", 3); sv_catpv(ST(0), PL_op_name[opnum]); }voidhash(sv) SV * sv CODE: char *s; STRLEN len; U32 hash = 0; char hexhash[19]; /* must fit "0xffffffffffffffff" plus trailing \0 */ s = SvPV(sv, len); PERL_HASH(hash, s, len); sprintf(hexhash, "0x%"UVxf, (UV)hash); ST(0) = sv_2mortal(newSVpv(hexhash, 0));#define cast_I32(foo) (I32)fooIVcast_I32(i) IV ivoidminus_c() CODE: PL_minus_c = TRUE;voidsave_BEGINs() CODE: PL_minus_c |= 0x10;SV *cstring(sv) SV * sv CODE: RETVAL = cstring(aTHX_ sv); OUTPUT: RETVALSV *cchar(sv) SV * sv CODE: RETVAL = cchar(aTHX_ sv); OUTPUT: RETVALvoidthreadsv_names() PPCODE:#ifdef USE_THREADS int i; STRLEN len = strlen(PL_threadsv_names); EXTEND(sp, len); for (i = 0; i < len; i++) PUSHs(sv_2mortal(newSVpvn(&PL_threadsv_names[i], 1)));#endif#define OP_next(o) o->op_next#define OP_sibling(o) o->op_sibling#define OP_desc(o) PL_op_desc[o->op_type]#define OP_targ(o) o->op_targ#define OP_type(o) o->op_type#define OP_seq(o) o->op_seq#define OP_flags(o) o->op_flags#define OP_private(o) o->op_privateMODULE = B PACKAGE = B::OP PREFIX = OP_B::OPOP_next(o) B::OP oB::OPOP_sibling(o) B::OP ochar *OP_name(o) B::OP o CODE: RETVAL = PL_op_name[o->op_type]; OUTPUT: RETVALvoidOP_ppaddr(o) B::OP o PREINIT: int i; SV *sv = sv_newmortal(); CODE: sv_setpvn(sv, "PL_ppaddr[OP_", 13); sv_catpv(sv, PL_op_name[o->op_type]); for (i=13; i<SvCUR(sv); ++i) SvPVX(sv)[i] = toUPPER(SvPVX(sv)[i]); sv_catpv(sv, "]"); ST(0) = sv;char *OP_desc(o) B::OP oPADOFFSETOP_targ(o) B::OP oU16OP_type(o) B::OP oU16OP_seq(o) B::OP oU8OP_flags(o) B::OP oU8OP_private(o) B::OP o#define UNOP_first(o) o->op_firstMODULE = B PACKAGE = B::UNOP PREFIX = UNOP_B::OP UNOP_first(o) B::UNOP o#define BINOP_last(o) o->op_lastMODULE = B PACKAGE = B::BINOP PREFIX = BINOP_B::OPBINOP_last(o) B::BINOP o
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -