/* ccop.c
*
* 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.
*
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ccop.h"
static
char
*opclassnames[] = {
"B::NULL"
,
"B::OP"
,
"B::UNOP"
,
"B::BINOP"
,
"B::LOGOP"
,
"B::CONDOP"
,
"B::LISTOP"
,
"B::PMOP"
,
"B::SVOP"
,
"B::GVOP"
,
"B::PVOP"
,
"B::CVOP"
,
"B::LOOP"
,
"B::COP"
};
static
opclass
cc_baseop(o)
OP *o;
{
return
OPc_BASEOP;
}
static
opclass
cc_unop(o)
OP *o;
{
return
OPc_UNOP;
}
static
opclass
cc_binop(o)
OP *o;
{
return
OPc_BINOP;
}
static
opclass
cc_logop(o)
OP *o;
{
return
OPc_LOGOP;
}
static
opclass
cc_condop(o)
OP *o;
{
return
OPc_CONDOP;
}
static
opclass
cc_listop(o)
OP *o;
{
return
OPc_LISTOP;
}
static
opclass
cc_pmop(o)
OP *o;
{
return
OPc_PMOP;
}
static
opclass
cc_svop(o)
OP *o;
{
return
OPc_SVOP;
}
static
opclass
cc_gvop(o)
OP *o;
{
return
OPc_GVOP;
}
static
opclass
cc_pvop(o)
OP *o;
{
return
OPc_PVOP;
}
static
opclass
cc_cvop(o)
OP *o;
{
return
OPc_CVOP;
}
static
opclass
cc_loop(o)
OP *o;
{
return
OPc_LOOP;
}
static
opclass
cc_cop(o)
OP *o;
{
return
OPc_COP;
}
/* Nullified ops with children still need to be able to find o->op_first */
static
opclass
cc_nullop(o)
OP *o;
{
return
((o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP);
}
static
opclass
cc_stub(o)
OP *o;
{
warn(
"compiler stub for %s, assuming BASEOP\n"
, ppnames[o->op_type]);
return
OPc_BASEOP;
/* XXX lie */
}
/*
* UNI(OP_foo) in toke.c returns token UNI or FUNC1 depending on whether
* bare parens were seen. perly.y uses OPf_SPECIAL to signal whether an
* OP or an UNOP was chosen.
* Frederic.Chauveau@pasteur.fr says we need to check for OPf_KIDS too.
*/
static
opclass
cc_baseop_or_unop(o)
OP *o;
{
return
((o->op_flags & OPf_SPECIAL) ? OPc_BASEOP :
(o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP);
}
/*
* 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
* a GVOP (and op_gv is the GV for the filehandle argument).
*/
static
opclass
cc_filestatop(o)
OP *o;
{
return
((o->op_flags & OPf_KIDS) ? OPc_UNOP :
(o->op_flags & OPf_REF) ? OPc_GVOP : OPc_BASEOP);
}
/*
* 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.
*/
static
opclass
cc_loopexop(o)
OP *o;
{
if
(o->op_flags & OPf_STACKED)
return
OPc_UNOP;
else
if
(o->op_flags & OPf_SPECIAL)
return
OPc_BASEOP;
else
return
OPc_PVOP;
}
static
opclass
cc_sassign(o)
OP *o;
{
return
((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP);
}
static
opclass (*ccopaddr[])_((OP *o)) = {
cc_nullop,
/* null */
cc_baseop,
/* stub */
cc_baseop_or_unop,
/* scalar */
cc_baseop,
/* pushmark */
cc_baseop,
/* wantarray */
cc_svop,
/* const */
cc_gvop,
/* gvsv */
cc_gvop,
/* gv */
cc_binop,
/* gelem */
cc_baseop,
/* padsv */
cc_baseop,
/* padav */
cc_baseop,
/* padhv */
cc_baseop,
/* padany */
cc_pmop,
/* pushre */
cc_unop,
/* rv2gv */
cc_unop,
/* rv2sv */
cc_unop,
/* av2arylen */
cc_unop,
/* rv2cv */
cc_svop,
/* anoncode */
cc_baseop_or_unop,
/* prototype */
cc_unop,
/* refgen */
cc_unop,
/* srefgen */
cc_baseop_or_unop,
/* ref */
cc_listop,
/* bless */
cc_baseop_or_unop,
/* backtick */
cc_listop,
/* glob */
cc_baseop_or_unop,
/* readline */
cc_stub,
/* rcatline */
cc_unop,
/* regcmaybe */
cc_logop,
/* regcomp */
cc_pmop,
/* match */
cc_pmop,
/* subst */
cc_logop,
/* substcont */
cc_pvop,
/* trans */
cc_sassign,
/* sassign */
cc_binop,
/* aassign */
cc_baseop_or_unop,
/* chop */
cc_baseop_or_unop,
/* schop */
cc_baseop_or_unop,
/* chomp */
cc_baseop_or_unop,
/* schomp */
cc_baseop_or_unop,
/* defined */
cc_baseop_or_unop,
/* undef */
cc_baseop_or_unop,
/* study */
cc_baseop_or_unop,
/* pos */
cc_unop,
/* preinc */
cc_unop,
/* i_preinc */
cc_unop,
/* predec */
cc_unop,
/* i_predec */
cc_unop,
/* postinc */
cc_unop,
/* i_postinc */
cc_unop,
/* postdec */
cc_unop,
/* i_postdec */
cc_binop,
/* pow */
cc_binop,
/* multiply */
cc_binop,
/* i_multiply */
cc_binop,
/* divide */
cc_binop,
/* i_divide */
cc_binop,
/* modulo */
cc_binop,
/* i_modulo */
cc_binop,
/* repeat */
cc_binop,
/* add */
cc_binop,
/* i_add */
cc_binop,
/* subtract */
cc_binop,
/* i_subtract */
cc_binop,
/* concat */
cc_listop,
/* stringify */
cc_binop,
/* left_shift */
cc_binop,
/* right_shift */
cc_binop,
/* lt */
cc_binop,
/* i_lt */
cc_binop,
/* gt */
cc_binop,
/* i_gt */
cc_binop,
/* le */
cc_binop,
/* i_le */
cc_binop,
/* ge */
cc_binop,
/* i_ge */
cc_binop,
/* eq */
cc_binop,
/* i_eq */
cc_binop,
/* ne */
cc_binop,
/* i_ne */
cc_binop,
/* ncmp */
cc_binop,
/* i_ncmp */
cc_binop,
/* slt */
cc_binop,
/* sgt */
cc_binop,
/* sle */
cc_binop,
/* sge */
cc_binop,
/* seq */
cc_binop,
/* sne */
cc_binop,
/* scmp */
cc_binop,
/* bit_and */
cc_binop,
/* bit_xor */
cc_binop,
/* bit_or */
cc_unop,
/* negate */
cc_unop,
/* i_negate */
cc_unop,
/* not */
cc_unop,
/* complement */
cc_listop,
/* atan2 */
cc_baseop_or_unop,
/* sin */
cc_baseop_or_unop,
/* cos */
cc_baseop_or_unop,
/* rand */
cc_baseop_or_unop,
/* srand */
cc_baseop_or_unop,
/* exp */
cc_baseop_or_unop,
/* log */
cc_baseop_or_unop,
/* sqrt */
cc_baseop_or_unop,
/* int */
cc_baseop_or_unop,
/* hex */
cc_baseop_or_unop,
/* oct */
cc_baseop_or_unop,
/* abs */
cc_baseop_or_unop,
/* length */
cc_listop,
/* substr */
cc_listop,
/* vec */
cc_listop,
/* index */
cc_listop,
/* rindex */
cc_listop,
/* sprintf */
cc_listop,
/* formline */
cc_baseop_or_unop,
/* ord */
cc_baseop_or_unop,
/* chr */
cc_listop,
/* crypt */
cc_baseop_or_unop,
/* ucfirst */
cc_baseop_or_unop,
/* lcfirst */
cc_baseop_or_unop,
/* uc */
cc_baseop_or_unop,
/* lc */
cc_baseop_or_unop,
/* quotemeta */
cc_unop,
/* rv2av */
cc_gvop,
/* aelemfast */
cc_binop,
/* aelem */
cc_listop,
/* aslice */
cc_baseop_or_unop,
/* each */
cc_baseop_or_unop,
/* values */
cc_baseop_or_unop,
/* keys */
cc_baseop_or_unop,
/* delete */
cc_baseop_or_unop,
/* exists */
cc_unop,
/* rv2hv */
cc_binop,
/* helem */
cc_listop,
/* hslice */
cc_listop,
/* unpack */
cc_listop,
/* pack */
cc_listop,
/* split */
cc_listop,
/* join */
cc_listop,
/* list */
cc_binop,
/* lslice */
cc_listop,
/* anonlist */
cc_listop,
/* anonhash */
cc_listop,
/* splice */
cc_listop,
/* push */
cc_baseop_or_unop,
/* pop */
cc_baseop_or_unop,
/* shift */
cc_listop,
/* unshift */
cc_listop,
/* sort */
cc_listop,
/* reverse */
cc_listop,
/* grepstart */
cc_logop,
/* grepwhile */
cc_listop,
/* mapstart */
cc_logop,
/* mapwhile */
cc_condop,
/* range */
cc_unop,
/* flip */
cc_unop,
/* flop */
cc_logop,
/* and */
cc_logop,
/* or */
cc_logop,
/* xor */
cc_condop,
/* cond_expr */
cc_logop,
/* andassign */
cc_logop,
/* orassign */
cc_unop,
/* method */
cc_unop,
/* entersub */
cc_unop,
/* leavesub */
cc_baseop_or_unop,
/* caller */
cc_listop,
/* warn */
cc_listop,
/* die */
cc_baseop_or_unop,
/* reset */
cc_listop,
/* lineseq */
cc_cop,
/* nextstate */
cc_cop,
/* dbstate */
cc_baseop,
/* unstack */
cc_baseop,
/* enter */
cc_listop,
/* leave */
cc_listop,
/* scope */
cc_loop,
/* enteriter */
cc_baseop,
/* iter */
cc_loop,
/* enterloop */
cc_binop,
/* leaveloop */
cc_listop,
/* return */
cc_loopexop,
/* last */
cc_loopexop,
/* next */
cc_loopexop,
/* redo */
cc_loopexop,
/* dump */
cc_loopexop,
/* goto */
cc_baseop_or_unop,
/* exit */
cc_listop,
/* open */
cc_baseop_or_unop,
/* close */
cc_listop,
/* pipe_op */
cc_baseop_or_unop,
/* fileno */
cc_baseop_or_unop,
/* umask */
cc_baseop_or_unop,
/* binmode */
cc_listop,
/* tie */
cc_baseop_or_unop,
/* untie */
cc_baseop_or_unop,
/* tied */
cc_listop,
/* dbmopen */
cc_baseop_or_unop,
/* dbmclose */
cc_listop,
/* sselect */
cc_listop,
/* select */
cc_baseop_or_unop,
/* getc */
cc_listop,
/* read */
cc_baseop_or_unop,
/* enterwrite */
cc_unop,
/* leavewrite */
cc_listop,
/* prtf */
cc_listop,
/* print */
cc_listop,
/* sysopen */
cc_listop,
/* sysread */
cc_listop,
/* syswrite */
cc_listop,
/* send */
cc_listop,
/* recv */
cc_baseop_or_unop,
/* eof */
cc_baseop_or_unop,
/* tell */
cc_listop,
/* seek */
cc_listop,
/* truncate */
cc_listop,
/* fcntl */
cc_listop,
/* ioctl */
cc_listop,
/* flock */
cc_listop,
/* socket */
cc_listop,
/* sockpair */
cc_listop,
/* bind */
cc_listop,
/* connect */
cc_listop,
/* listen */
cc_listop,
/* accept */
cc_listop,
/* shutdown */
cc_listop,
/* gsockopt */
cc_listop,
/* ssockopt */
cc_baseop_or_unop,
/* getsockname */
cc_baseop_or_unop,
/* getpeername */
cc_filestatop,
/* lstat */
cc_filestatop,
/* stat */
cc_filestatop,
/* ftrread */
cc_filestatop,
/* ftrwrite */
cc_filestatop,
/* ftrexec */
cc_filestatop,
/* fteread */
cc_filestatop,
/* ftewrite */
cc_filestatop,
/* fteexec */
cc_filestatop,
/* ftis */
cc_filestatop,
/* fteowned */
cc_filestatop,
/* ftrowned */
cc_filestatop,
/* ftzero */
cc_filestatop,
/* ftsize */
cc_filestatop,
/* ftmtime */
cc_filestatop,
/* ftatime */
cc_filestatop,
/* ftctime */
cc_filestatop,
/* ftsock */
cc_filestatop,
/* ftchr */
cc_filestatop,
/* ftblk */
cc_filestatop,
/* ftfile */
cc_filestatop,
/* ftdir */
cc_filestatop,
/* ftpipe */
cc_filestatop,
/* ftlink */
cc_filestatop,
/* ftsuid */
cc_filestatop,
/* ftsgid */
cc_filestatop,
/* ftsvtx */
cc_filestatop,
/* fttty */
cc_filestatop,
/* fttext */
cc_filestatop,
/* ftbinary */
cc_baseop_or_unop,
/* chdir */
cc_listop,
/* chown */
cc_baseop_or_unop,
/* chroot */
cc_listop,
/* unlink */
cc_listop,
/* chmod */
cc_listop,
/* utime */
cc_listop,
/* rename */
cc_listop,
/* link */
cc_listop,
/* symlink */
cc_baseop_or_unop,
/* readlink */
cc_listop,
/* mkdir */
cc_baseop_or_unop,
/* rmdir */
cc_listop,
/* open_dir */
cc_baseop_or_unop,
/* readdir */
cc_baseop_or_unop,
/* telldir */
cc_listop,
/* seekdir */
cc_baseop_or_unop,
/* rewinddir */
cc_baseop_or_unop,
/* closedir */
cc_baseop,
/* fork */
cc_baseop,
/* wait */
cc_listop,
/* waitpid */
cc_listop,
/* system */
cc_listop,
/* exec */
cc_listop,
/* kill */
cc_baseop,
/* getppid */
cc_baseop_or_unop,
/* getpgrp */
cc_listop,
/* setpgrp */
cc_listop,
/* getpriority */
cc_listop,
/* setpriority */
cc_baseop,
/* time */
cc_baseop,
/* tms */
cc_baseop_or_unop,
/* localtime */
cc_baseop_or_unop,
/* gmtime */
cc_baseop_or_unop,
/* alarm */
cc_baseop_or_unop,
/* sleep */
cc_listop,
/* shmget */
cc_listop,
/* shmctl */
cc_listop,
/* shmread */
cc_listop,
/* shmwrite */
cc_listop,
/* msgget */
cc_listop,
/* msgctl */
cc_listop,
/* msgsnd */
cc_listop,
/* msgrcv */
cc_listop,
/* semget */
cc_listop,
/* semctl */
cc_listop,
/* semop */
cc_baseop_or_unop,
/* require */
cc_unop,
/* dofile */
cc_baseop_or_unop,
/* entereval */
cc_unop,
/* leaveeval */
cc_logop,
/* entertry */
cc_listop,
/* leavetry */
cc_baseop_or_unop,
/* ghbyname */
cc_listop,
/* ghbyaddr */
cc_baseop,
/* ghostent */
cc_baseop_or_unop,
/* gnbyname */
cc_listop,
/* gnbyaddr */
cc_baseop,
/* gnetent */
cc_baseop_or_unop,
/* gpbyname */
cc_listop,
/* gpbynumber */
cc_baseop,
/* gprotoent */
cc_listop,
/* gsbyname */
cc_listop,
/* gsbyport */
cc_baseop,
/* gservent */
cc_baseop_or_unop,
/* shostent */
cc_baseop_or_unop,
/* snetent */
cc_baseop_or_unop,
/* sprotoent */
cc_baseop_or_unop,
/* sservent */
cc_baseop,
/* ehostent */
cc_baseop,
/* enetent */
cc_baseop,
/* eprotoent */
cc_baseop,
/* eservent */
cc_baseop_or_unop,
/* gpwnam */
cc_baseop_or_unop,
/* gpwuid */
cc_baseop,
/* gpwent */
cc_baseop,
/* spwent */
cc_baseop,
/* epwent */
cc_baseop_or_unop,
/* ggrnam */
cc_baseop_or_unop,
/* ggrgid */
cc_baseop,
/* ggrent */
cc_baseop,
/* sgrent */
cc_baseop,
/* egrent */
cc_baseop,
/* getlogin */
cc_listop,
/* syscall */
};
opclass
cc_opclass(o)
OP * o;
{
return
o ? (*ccopaddr[o->op_type])(o) : OPc_NULL;
}
char
*
cc_opclassname(o)
OP * o;
{
return
opclassnames[o ? (*ccopaddr[o->op_type])(o) : OPc_NULL];
}