内容

名称

B - Perl 编译器后端

概要

use B;

描述

B 模块提供了一些类,允许 Perl 程序深入了解其内部结构。它是用于实现 Perl 编译器“后端”的模块。编译器的使用不需要了解此模块:有关用户可见部分,请参见 O 模块。B 模块对想要编写新的编译器后端的人有用。本文档假设读者对 perl 的内部结构有相当的了解,包括 SV、OP 以及程序的内部符号表和语法树等内容。

概述

B 模块包含一组用于查询 Perl 解释器当前状态的实用函数;通常这些函数返回来自 B::SV 和 B::OP 类或其派生类的对象。这些类反过来定义了用于查询结果对象关于其自身内部状态的方法。

实用函数

B 模块导出各种函数:一些是简单的实用函数,另一些则为 Perl 程序提供了一种获取内部对象初始“句柄”的方法。

返回 B::SVB::AVB::HVB::CV 对象的函数

有关这些对象的类层次结构以及可以调用它们的方法的描述,请参见下面的 "类概述""与 SV 相关的类"

sv_undef

返回与 C 变量 sv_undef 相对应的 SV 对象。

sv_yes

返回与 C 变量 sv_yes 相对应的 SV 对象。

sv_no

返回与 C 变量 sv_no 相对应的 SV 对象。

svref_2object(SVREF)

接受对任何 Perl 值的引用,并将引用的值转换为适当的 B::OP 派生类或 B::SV 派生类中的对象。除了 main_root 等函数之外,这是获取内部 perl 数据结构的初始“句柄”的主要方法,然后可以使用其他访问方法对其进行跟踪。

返回的对象仅在底层 OP 和 SV 继续存在时才有效。不要尝试在底层结构被释放后使用该对象。

amagic_generation

返回与 C 变量 amagic_generation 对应的 SV 对象。从 Perl 5.18 开始,这只是 PL_na 的别名,因此其值毫无意义。

init_av

返回表示 INIT 块的 AV 对象(即 B::AV 类)。

check_av

返回表示 CHECK 块的 AV 对象(即 B::AV 类)。

unitcheck_av

返回表示 UNITCHECK 块的 AV 对象(即 B::AV 类)。

begin_av

返回表示 BEGIN 块的 AV 对象(即 B::AV 类)。

end_av

返回表示 END 块的 AV 对象(即 B::AV 类)。

comppadlist

返回全局 comppadlist 的 PADLIST 对象(即 B::PADLIST 类)。在 Perl 5.16 及更早版本中,它返回 AV 对象(B::AV 类)。

regex_padav

仅当 perl 使用 ithreads 编译时。

main_cv

返回与 Perl 程序主部分相对应的(伪造的)CV。

用于检查符号表的函数

walksymtable(SYMREF, METHOD, RECURSE, PREFIX)

从 SYMREF 开始遍历符号表,并对访问的每个符号(B::GV 对象)调用 METHOD。当遍历到达包符号(例如 "Foo::")时,它会调用 RECURSE,传入符号名称,并且只有在该子例程返回 true 时才会递归到该包中。

PREFIX 是您正在遍历的 SYMREF 的名称。

例如

# Walk CGI's symbol table calling print_subs on each symbol.
# Recurse only into CGI::Util::
walksymtable(\%CGI::, 'print_subs',
             sub { $_[0] eq 'CGI::Util::' }, 'CGI::');

print_subs() 是您声明的 B::GV 方法。另请参见下面的 "B::GV 方法"

返回 B::OP 对象或用于遍历操作树的函数

有关这些对象的类层次结构以及可以对它们调用的方法的描述,请参见下面的 "类概述""与操作相关的类"

main_root

返回 Perl 程序主部分的根操作(即适当的 B::OP 派生类中的对象)。

main_start

返回 Perl 程序主部分的起始操作。

walkoptree(OP, METHOD)

对以 OP 为基础的语法树进行树遍历,并对访问的每个操作调用 METHOD。每个节点都在其子节点之前被访问。如果 walkoptree_debug(见下文)已被调用以打开调试,则在调用 METHOD 之前,会对每个操作调用 walkoptree_debug 方法。

walkoptree_debug(DEBUG)

返回 walkoptree 的当前调试标志。如果可选的 DEBUG 参数非零,则将调试标志设置为该参数。有关调试标志的作用,请参见上面 walkoptree 的描述。

杂项实用函数

ppname(OPNUM)

返回操作数 OPNUM 的 PP 函数名称(例如“pp_add”)。

hash(STR)

返回一个字符串,格式为“0x...”表示 perl 在字符串 STR 上使用的内部哈希函数的值。

cast_I32(I)

将 I 转换为该 perl 使用的内部 I32 类型。

minus_c

执行等效于 -c 命令行选项的操作。显然,这仅在 BEGIN 块中才有用,否则标志设置得太晚。

cstring(STR)

返回 STR 的双引号包围的转义版本,该版本可用作 C 源代码中的字符串。

perlstring(STR)

返回 STR 的双引号包围的转义版本,该版本可用作 Perl 源代码中的字符串。

safename(STR)

此函数返回的字符串,如果第一个字符是控制字符,则修改第一个字符。它首先将其转换为 ^X 格式,以便“\cG”变为“^G”。这在 B::GV::SAFENAME 内部使用,但您可以直接调用它。

class(OBJ)

返回对象的类,不包括类名中第一个 "::" 之前的部分。例如,这用于将 "B::UNOP" 转换为 "UNOP"

threadsv_names

这曾经提供对旧的 5.005 线程模块的支持。现在它什么也不做。

导出实用变量

@optype
my $op_type = $optype[$op_type_num];

一个简单的映射,将操作类型编号映射到其类型(如“COP”或“BINOP”)。

@specialsv_name
my $sv_name = $specialsv_name[$sv_index];

某些 SV 类型被认为是“特殊的”。它们由 B::SPECIAL 表示,并由 specialsv_list 中的数字引用。此数组将该数字映射回 SV 的名称(如“Nullsv”或“&PL_sv_undef”)。

类概述

Perl 内部用于保存 SV 和 OP 信息的 C 结构(PVIV、AV、HV、...、OP、SVOP、UNOP、...)是根据类层次结构建模的,B 模块通过真正的对象层次结构提供对它们的访问。指向其他对象的结构字段(无论是 SV 类型还是 OP 类型)由 B 模块表示为适当类的 Perl 对象。

B 模块的大部分内容是用于访问这些结构字段的方法。

请注意,所有访问都是只读的。您不能使用此模块修改内部结构。此外,请注意,此模块创建的 B::OP 和 B::SV 对象仅在底层对象存在时有效;它们的创建不会增加底层对象的引用计数。尝试访问已释放对象的字段将导致无法理解的结果,甚至更糟。

B::IV、B::NV、B::PV、B::PVIV、B::PVNV、B::PVMG、B::PVLV、B::AV、B::HV、B::CV、B::GV、B::FM、B::IO。这些类以显而易见的方式对应于具有类似名称的底层 C 结构。继承层次结构模仿底层的 C“继承”。

                   B::SV
                     |
        +------------+------------+
        |            |            |
      B::PV        B::IV        B::NV
       /  \         /           /
      /    \       /           /
B::INVLIST  B::PVIV           /
                 \           /
                  \         /
                   \       /
                    B::PVNV
                       |
                       |
                    B::PVMG
                       |
   +-------+-------+---+---+-------+-------+
   |       |       |       |       |       |
 B::AV   B::GV   B::HV   B::CV   B::IO B::REGEXP
           |               |
           |               |
        B::PVLV          B::FM

访问方法对应于底层 C 宏的字段访问,通常删除前导的“类指示”前缀(Sv、Av、Hv、...)。前导前缀仅在删除会导致方法名称冲突的情况下保留。例如,GvREFCNT 保持原样,因为它的缩写会与“超类”方法 REFCNT(对应于 C 函数 SvREFCNT)发生冲突。

B::SV 方法

REFCNT
FLAGS
IsBOOL

如果 SV 是布尔值(真或假),则返回真。然后,您可以使用 TRUE 检查该值是真还是假。

my $something = ( 1 == 1 ) # boolean true
             || ( 1 == 0 ) # boolean false
             || 42         # IV true
             || 0;         # IV false
my $sv = B::svref_2object(\$something);

say q[Not a boolean value]
    if ! $sv->IsBOOL;

say q[This is a boolean with value: true]
    if   $sv->IsBOOL && $sv->TRUE_nomg;

say q[This is a boolean with value: false]
    if   $sv->IsBOOL && ! $sv->TRUE_nomg;
object_2svref

返回指向此 B::SV 对象的对应常规标量的引用。换句话说,此方法是 svref_2object() 子例程的逆运算。此标量及其指向的其他数据应视为只读:修改它们既不安全也不保证产生合理的效果。

TRUE

返回一个布尔值,指示 Perl 是否会将 SV 评估为真或假。

警告 此调用执行“获取”魔法。如果您只想检查此 SV 的性质,请使用 TRUE_nomg 帮助程序。

这是 SvTRUE($sv) 的别名。

TRUE_nomg

检查值是否为真(不执行“获取”魔法)。返回一个布尔值,指示 Perl 是否会将 SV 评估为真或假。

这是 SvTRUE_nomg($sv) 的别名。

B::IV 方法

IV

返回 IV 的值,解释为有符号整数。如果 FLAGS & SVf_IVisUV,这将产生误导。也许您想要 int_value 方法?

IVX
UVX
int_value

此方法返回 IV 的值作为整数。它与 IV 不同,因为它无论存储为有符号还是无符号,都会返回正确的值。

needs64bits
packiv

B::NV 方法

NV
NVX
COP_SEQ_RANGE_LOW
COP_SEQ_RANGE_HIGH

最后这两个仅对垫名称 SV 有效。它们在 Perl 5.22 之前只存在于 B::NV 类中。在 5.22 中,它们被移到了 B::PADNAME 类。

B::RV 方法

RV

B::PV 方法

PV

此方法是您通常想要的方法。它使用结构中的长度和偏移信息构建一个字符串:对于普通标量,它将返回您从 Perl 中看到的字符串,即使它包含空字符。

RV

与 B::RV::RV 相同,只是如果 PV 不是引用,它将 die()。

PVX

这种方法不太常用。它假设存储在结构体中的字符串以空字符结尾,并忽略长度信息。

如果您需要从 padname 数组中获取词法变量的名称,则应使用此方法。词法变量名始终以空字符结尾,并且长度字段 (CUR) 被重载用于其他目的,因此在这里不可靠。

CUR

此方法返回内部长度字段,该字段包含内部字节数,不一定等于逻辑字符数。

LEN

此方法返回为存储字符串而分配的字节数(通过 malloc)。如果标量不“拥有”字符串,则为 0。

B::PVMG 方法

MAGIC
SvSTASH

B::MAGIC 方法

MOREMAGIC
precomp

仅对 r-magic 有效,返回生成正则表达式的字符串。

PRIVATE
TYPE
FLAGS
OBJ

如果在 r-magic 上调用,将调用 die()。

PTR
REGEX

仅对 r-magic 有效,返回存储在 MAGIC 中的 REGEX 的整数值。

B::INVLIST 方法

prev_index

返回上次 invlist_search() 的缓存结果(内部使用)

is_offset

返回一个布尔值(0 或 1),用于判断 invlist 是否使用偏移量。如果为 false,则列表从代码点 U+0000 开始。如果为 true,则列表从以下元素开始。

array_len

返回一个整数,表示用于定义 invlist 的数组的大小。

get_invlist_array

此方法返回一个整数列表,表示 invlist 使用的数组。注意:在迭代 invlist 的过程中不能使用此方法,否则会引发异常。

B::PVLV 方法

TARGOFF
TARGLEN
TYPE
TARG

B::BM 方法

USEFUL
PREVIOUS
RARE
TABLE

B::REGEXP 方法

REGEX
precomp
qr_anoncv
compflags

最后两个是在 Perl 5.22 中添加的。

B::GV 方法

is_empty

如果 GV 的 GP 字段为 NULL,则此方法返回 TRUE。

NAME
SAFENAME

此方法返回 glob 的名称,但如果名称的第一个字符是控制字符,则它会先将其转换为 ^X,因此 *^G 将返回 "^G" 而不是 "\cG"。

如果您想打印出变量的名称,这很有用。如果您将自己限制在编译时存在的 glob,那么结果应该是明确的,因为像 ${"^G"} = 1 这样的代码被编译为两个操作 - 一个常量字符串和一个解引用 (rv2gv) - 因此 glob 是在运行时创建的。

如果您在运行时处理 glob,并且需要区分 *^G 和 *{"^G"},那么您应该使用原始 NAME 方法。

STASH
SV
IO
FORM
AV
HV
EGV
CV
CVGEN
LINE
FILE
FILEGV
GvREFCNT
FLAGS
GPFLAGS

最后一个仅在 perl 5.22.0 及更高版本中存在。

B::IO 方法

B::IO 对象从 IO 对象派生,您将从 IO 对象本身获得更多信息。

例如

$gvio = B::svref_2object(\*main::stdin)->IO;
$IO = $gvio->object_2svref();
$fd = $IO->fileno();
LINES
PAGE
PAGE_LEN
LINES_LEFT
TOP_NAME
TOP_GV
FMT_NAME
FMT_GV
BOTTOM_NAME
BOTTOM_GV
SUBPROCESS
IoTYPE

表示 IO 处理程序类型的字符。

-     STDIN/OUT
I     STDIN/OUT/ERR
<     read-only
>     write-only
a     append
+     read and write
s     socket
|     pipe
I     IMPLICIT
#     NUMERIC
space closed handle
\0    closed internal handle
IoFLAGS
IsSTD

接受一个参数('stdin' | 'stdout' | 'stderr'),如果对象的 IoIFP 等于以参数形式传递的名称的句柄,则返回 true;例如,$io->IsSTD('stderr') 如果 IoIFP($io) == PerlIO_stderr() 则为 true。

B::AV 方法

FILL
MAX
ARRAY
ARRAYelt

类似于 ARRAY,但接受一个索引作为参数,以获取单个元素,而不是所有元素的列表。

B::CV 方法

STASH
START
ROOT
GV
FILE
DEPTH
PADLIST

返回一个 B::PADLIST 对象。

OUTSIDE
OUTSIDE_SEQ
XSUB
XSUBANY

对于常量子例程,返回子例程返回的常量 SV。

CvFLAGS
const_sv
NAME_HEK

返回词法子例程的名称,否则返回 undef

B::HV 方法

FILL
MAX
KEYS
RITER
NAME
ARRAY

B::OPB::UNOPB::UNOP_AUXB::BINOPB::LOGOPB::LISTOPB::PMOPB::SVOPB::PADOPB::PVOPB::LOOPB::COPB::METHOP

这些类以明显的方式对应于同名底层 C 结构。继承层次结构模仿底层 C 的“继承”。

                         B::OP
                           |
           +----------+---------+--------+-------+---------+
           |          |         |        |       |         |
        B::UNOP    B::SVOP  B::PADOP  B::COP  B::PVOP  B::METHOP
           |
       +---+---+---------+
       |       |         |
   B::BINOP  B::LOGOP  B::UNOP_AUX
       |
       |
   B::LISTOP
       |
   +---+---+
   |       |
B::LOOP   B::PMOP

访问方法对应于底层 C 结构字段名,去掉了开头的“类指示”前缀("op_")。

B::OP 方法

这些方法获取 OP 数据结构中同名字段的值。有关更多信息,请参阅 op.h 的顶部。

next
sibling
parent

返回 OP 的父级。如果它没有父级,或者如果您的 perl 没有使用 -DPERL_OP_PARENT 构建,则返回 NULL。

请注意,全局变量 $B::OP::does_parent 在不支持 parent 方法的旧版 perl 中未定义,在支持该方法但没有使用 -DPERL_OP_PARENT 构建的 perl 中定义但为假,否则为真。

name

这将返回操作名称作为字符串(例如“add”、“rv2av”)。

ppaddr

这将返回函数名称作为字符串(例如“PL_ppaddr[OP_ADD]”、“PL_ppaddr[OP_RV2AV]”)。

desc

这将从全局 C PL_op_desc 数组中返回操作描述(例如“addition” “array deref”)。

targ
type
opt
flags
private
spare

B::UNOP 方法

first

B::UNOP_AUX 方法(自 5.22 起)

aux_list(cv)

此方法返回操作的辅助数据结构中的元素列表,如果不存在辅助数据结构,则返回空列表。 返回值取决于对象的类型,但通常是 B::IVB::GV 等对象的集合。 cv 是表示包含操作的子例程的 B::CV 对象。

string(cv)

此方法返回对象的文本表示形式(可能对反解析和调试有用),如果操作类型不支持此方法,则返回空字符串。 cv 是表示包含操作的子例程的 B::CV 对象。

B::BINOP 方法

last

B::LOGOP 方法

other

B::LISTOP 方法

children

B::PMOP 方法

pmreplroot
pmreplstart
pmflags
precomp
pmoffset

仅当 perl 使用 ithreads 编译时。

code_list

自 Perl 5.17.1 起

pmregexp

在 Perl 5.22 中添加,此方法返回与操作关联的 B::REGEXP。 虽然 PMOP 在线程化构建中实际上没有 pmregexp 字段,但此方法仍然返回线程下的正则表达式,以方便起见。

B::SVOP 方法

sv
gv

B::PADOP 方法

padix

B::PVOP 方法

pv

B::LOOP 方法

redoop
nextop
lastop

B::COP 方法

B::COP 类用于 "nextstate" 和 "dbstate" 操作。从 Perl 5.22 开始,它也用于最初作为 COP 的 "null" 操作。

label
stash
stashpv
stashoff (仅限线程)
file
cop_seq
line
warnings
io
hints
hints_hash

B::METHOP 方法 (自 Perl 5.22 起)

first
meth_sv

Perl 5.18 引入了一个新的类,B::PADLIST,由 B::CV 的 PADLIST 方法返回。

Perl 5.22 引入了 B::PADNAMELIST 和 B::PADNAME 类。

B::PADLIST 方法

MAX
ARRAY

一个 pad 列表。第一个是包含名称的 B::PADNAMELIST。其余的目前是 B::AV 对象,但这可能会在将来的版本中发生变化。

ARRAYelt

类似于 ARRAY,但接受一个索引作为参数,以获取单个元素,而不是所有元素的列表。

NAMES

此方法在 5.22 中引入,返回 B::PADNAMELIST。它等效于带有 0 个参数的 ARRAYelt

REFCNT
id

此方法在 5.22 中引入,返回相同 padlist 克隆共享的 ID。

outid

此方法也在 5.22 中添加,返回外部 padlist 的 ID。

B::PADNAMELIST 方法

MAX
ARRAY
ARRAYelt

这两个方法返回 pad 名称,使用 B::SPECIAL 对象表示空指针,使用 B::PADNAME 对象表示其他情况。

REFCNT

B::PADNAME 方法

PV
PVX
LEN
REFCNT
GEN
FLAGS

为了向后兼容,如果设置了 PADNAMEt_OUTER 标志,FLAGS 方法也会添加 SVf_FAKE 标志。

TYPE

表示类型词法作用域的存储区的 B::HV 对象。

SvSTASH

TYPE 的向后兼容别名。

OURSTASH

表示 'our' 变量的存储区的 B::HV 对象。

PROTOCV

'my' 子例程的原型 CV。

COP_SEQ_RANGE_LOW
COP_SEQ_RANGE_HIGH

表示词法作用域可见范围的序列号。如果设置了 PADNAMEt_OUTER,则无意义。

PARENT_PAD_INDEX

仅当设置了 PADNAMEt_OUTER 时才有意义。

PARENT_FAKELEX_FLAGS

仅当设置了 PADNAMEt_OUTER 时才有意义。

IsUndef

返回一个布尔值,用于检查 padname 是否为 PL_padname_undef。

$B::overlay

虽然 optree 是只读的,但有一个覆盖机制允许您覆盖各种 B::*OP 方法为特定操作返回的值。$B::overlay 应该设置为引用一个两层哈希:按操作地址索引,然后是方法名称。每当调用操作方法时,如果哈希中存在该值,则返回该值。此机制由 B::Deparse 用于“撤消”某些优化。例如

local $B::overlay = {};
...
if ($op->name eq "foo") {
    $B::overlay->{$$op} = {
            name => 'bar',
            next => $op->next->next,
    };
}
...
$op->name # returns "bar"
$op->next # returns the next op but one

作者

Malcolm Beattie,[email protected]