B - Perl 編譯器後端
use B;
B
模組提供類別,讓 Perl 程式深入自己的內部。這是用於實作 Perl 編譯器「後端」的模組。使用編譯器不需要知道這個模組:請參閱 O 模組,以取得使用者可見的部分。B
模組對想要撰寫新的編譯器後端的人很有用。此文件假設讀者對 perl 的內部結構有相當的了解,包括 SV、OP,以及程式的內部符號表和語法樹等內容。
B
模組包含一組用於查詢 Perl 解譯器目前狀態的公用函式;通常這些函式會傳回 B::SV 和 B::OP 類別的物件,或其衍生類別。這些類別進而定義方法,用於查詢結果物件的內部狀態。
B
模組匯出各種函式:有些是簡單的公用函式,有些提供 Perl 程式一個方法,用於取得內部物件的初始「控制代碼」。
B::SV
、B::AV
、B::HV
和 B::CV
物件的函式有關這些物件的類別階層和可在其上呼叫的方法的說明,請參閱下方、「類別概觀」和「SV 相關類別」。
傳回對應於 C 變數 sv_undef
的 SV 物件。
傳回對應於 C 變數 sv_yes
的 SV 物件。
傳回對應於 C 變數 sv_no
的 SV 物件。
取得任何 Perl 值的參考,並將所參考的值轉換為適當的 B::OP 或 B::SV 衍生類別中的物件。除了 main_root
等函式外,這是取得內部 Perl 資料結構的初始「控制權」的主要方法,然後可以使用其他存取方法。
傳回的物件只會在底層 OP 和 SV 持續存在時有效。底層結構釋放後,請勿嘗試使用物件。
傳回對應於 C 變數 amagic_generation
的 SV 物件。從 Perl 5.18 開始,這只是一個別名,指向 PL_na
,因此其值沒有意義。
傳回表示 INIT 區塊的 AV 物件(即 B::AV 類別中)。
傳回表示 CHECK 區塊的 AV 物件(即 B::AV 類別中)。
傳回表示 UNITCHECK 區塊的 AV 物件(即 B::AV 類別中)。
傳回表示 BEGIN 區塊的 AV 物件(即 B::AV 類別中)。
傳回表示 END 區塊的 AV 物件(即 B::AV 類別中)。
傳回全域 comppadlist 的 PADLIST 物件(即 B::PADLIST 類別中)。在 Perl 5.16 及更早版本中,它傳回 AV 物件(B::AV 類別)。
只有當 Perl 是使用 ithreads 編譯時。
傳回對應於 Perl 程式主體部分的(偽造)CV。
從 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
物件或用於遍歷 op 樹有關這些物件的類別階層和可呼叫它們的方法的說明,請參閱以下內容,"類別總覽" 和 "與 OP 相關的類別"。
傳回 Perl 程式主體的根部 op(即 B::OP 派生類別中的物件)。
傳回 Perl 程式主體的起始 op。
根據 OP 進行語法樹的樹狀遍歷,並在訪問的每個 op 上呼叫 METHOD。每個節點在它的子節點之前被訪問。如果已呼叫 walkoptree_debug
(請參閱以下內容)以開啟除錯,則在呼叫 METHOD 之前,會在每個 op 上呼叫方法 walkoptree_debug
。
傳回 walkoptree
的目前除錯旗標。如果選擇性的 DEBUG 參數是非零,它會將除錯旗標設定為該值。請參閱上方 walkoptree
的說明,以了解除錯旗標的作用。
傳回 op 號碼 OPNUM 的 PP 函數名稱(例如 "pp_add")。
傳回字串 "0x...",代表 perl 在字串 STR 上使用的內部雜湊函數值。
將 I 轉換為 perl 使用的內部 I32 類型。
執行等同於 -c
命令列選項的動作。顯然,這僅在 BEGIN 區塊中才有用,否則旗標會設定得太晚。
傳回 STR 的雙引號包圍轉譯版本,可用於 C 原始碼中的字串。
傳回 STR 的雙引號包圍轉譯版本,可用於 Perl 原始碼中的字串。
此函數傳回字串,如果第一個字元是控制字元,則會修改。它會先轉換成 ^X 格式,因此 "\cG" 會變成 "^G"。這是 B::GV::SAFENAME 內部使用的,但你可以直接呼叫它。
傳回物件的類別,不包含類別名稱中第一個 "::"
之前的部分。例如,這會將 "B::UNOP"
轉換成 "UNOP"
。
這用於提供舊版 5.005 執行緒模組的支援。它現在不執行任何動作。
my $op_type = $optype[$op_type_num];
op 類型數字到其類型(例如 'COP' 或 'BINOP')的簡單對應。
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
)衝突。
如果 SV 是布林值(真或假),則傳回 true。然後您可以使用 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;
傳回對應於此 B::SV 物件的常規純量的參考。換句話說,此方法是 svref_2object() 子例程的反向操作。此純量及其指向的其他資料應視為唯讀:修改它們既不安全,也無法保證會產生合理的影響。
傳回布林值,表示 Perl 是否會將 SV 評估為真或假。
警告此呼叫會執行「取得」魔法。如果您只想檢查此 SV 的性質,請使用 TRUE_nomg
輔助程式。
這是 SvTRUE($sv)
的別名。
檢查值是否為真(不執行「取得」魔法)。傳回布林值,表示 Perl 是否會將 SV 評估為真或假。
這是 SvTRUE_nomg($sv)
的別名。
傳回 IV 的值,解釋為有號整數。如果 FLAGS & SVf_IVisUV
,這會產生誤導。或許您想要 int_value
方法?
此方法傳回 IV 的值作為整數。它與 IV
的不同之處在於,它傳回正確的值,無論它是以有號或無號儲存。
最後這兩個僅對 pad 名稱 SV 有效。在 Perl 5.22 之前,它們僅存在於 B::NV 類別中。在 5.22 中,它們被移至 B::PADNAME 類別。
此方法通常是您想要的。它使用結構中的長度和偏移資訊來建構字串:對於一般標量,它會傳回您從 Perl 看到的字串,即使它包含空字元。
與 B::RV::RV 相同,但如果 PV 不是參考,它會執行 die()。
此方法較不常使用。它假設儲存在結構中的字串以空字元終止,並忽略長度資訊。
如果您需要從 padname 陣列取得詞彙變數的名稱,則這是適當的方法。詞彙變數名稱總是儲存為空字元終止符,而長度欄位 (CUR) 會因其他目的而過載,因此無法在此依賴它。
此方法傳回內部長度欄位,其中包含內部位元組數,不一定是邏輯字元的數目。
此方法傳回配置給 malloc 以儲存字串的位元組數。如果標量不「擁有」字串,則為 0。
僅對 r-magic 有效,傳回產生正規表示式的字串。
如果在 r-magic 上呼叫,將會 die()。
僅在 r-magic 上有效,傳回儲存在 MAGIC 中的正規表示式的整數值。
傳回 invlist_search() 的快取結果 (內部使用)
傳回布林值 (0 或 1) 以得知 invlist 是否使用偏移量。為 false 時,清單從碼點 U+0000 開始。為 true 時,清單從下列元素開始。
傳回用於定義 invlist 的陣列大小的整數。
此方法傳回代表 invlist 使用的陣列的整數清單。注意:這無法在迭代 invlist 中間使用,否則會 croak。
如果 GV 的 GP 欄位為 NULL,此方法傳回 TRUE。
此方法傳回 glob 的名稱,但如果名稱的第一個字元是控制字元,則會先將其轉換為 ^X,因此 *^G 會傳回 "^G" 而不是 "\cG"。
如果您想要列印變數的名稱,這會很有用。如果您將自己限制在編譯時存在的 glob,則結果應該是明確的,因為像 ${"^G"} = 1
的程式碼編譯為兩個運算式 - 一個常數字串和一個解除參考 (rv2gv) - 因此 glob 會在執行時建立。
如果您在執行時使用 glob,並且需要區分 *^G 和 *{"^G"},則應使用原始 NAME 方法。
最後一個只存在於 perl 5.22.0 及更新版本中。
B::IO 物件衍生自 IO 物件,而且您將從 IO 物件本身取得更多資訊。
例如
$gvio = B::svref_2object(\*main::stdin)->IO;
$IO = $gvio->object_2svref();
$fd = $IO->fileno();
象徵 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
取得一個引數('stdin' | 'stdout' | 'stderr'),如果物件的 IoIFP 等於作為引數傳遞的名稱,則傳回 true;亦即,如果 IoIFP($io) == PerlIO_stderr(),則 $io->IsSTD('stderr') 為 true。
傳回一個 B::PADLIST 物件。
對於常數子常式,傳回子常式傳回的常數 SV。
傳回詞彙子常式的名稱,否則為 undef
。
B::OP
、B::UNOP
、B::UNOP_AUX
、B::BINOP
、B::LOGOP
、B::LISTOP
、B::PMOP
、B::SVOP
、B::PADOP
、B::PVOP
、B::LOOP
、B::COP
、B::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_"
)。
這些方法取得 OP 資料結構中類似名稱欄位的值。更多資訊請參閱 op.h
的頂端。
傳回 OP 的父項。如果沒有父項,或您的 perl 不是使用 -DPERL_OP_PARENT
建置,則傳回 NULL。
請注意,在不支援 parent
方法的較舊 perl 中,全域變數 $B::OP::does_parent
未定義,在支援此方法但未使用 -DPERL_OP_PARENT
建置的 perl 中,此變數已定義但為 false,否則為 true。
傳回 op 名稱作為字串 (例如「add」、「rv2av」)。
傳回函式名稱作為字串 (例如「PL_ppaddr[OP_ADD]」、「PL_ppaddr[OP_RV2AV]」)。
這會傳回來自全域 C PL_op_desc 陣列的 op 說明(例如「加法」、「陣列解除參考」)。
這會傳回 op 的 aux 資料結構元素清單,或是在沒有 aux 的情況下傳回 null 清單。傳回的內容會根據物件類型而有所不同,但通常會是 B::IV
、B::GV
等物件的集合。cv
是表示包含 op 的子程式的 B::CV
物件。
這會傳回物件的文字表示形式(可能對剖析和除錯很有用),或是在 op 類型不支援此功能的情況下傳回空字串。cv
是表示包含 op 的子程式的 B::CV
物件。
只有當 Perl 是使用 ithreads 編譯時。
自 perl 5.17.1 起
在 perl 5.22 中新增,此方法會傳回與 op 相關聯的 B::REGEXP。雖然 PMOP 在執行緒建置下實際上沒有 pmregexp
欄位,但此方法仍會傳回執行緒下的正規表示式,以方便使用。
B::COP
類別用於「nextstate」和「dbstate」操作。自 Perl 5.22 起,它也用於最初為 COP 的「null」操作。
Perl 5.18 導入了一個新的類別 B::PADLIST,由 B::CV 的 PADLIST
方法傳回。
Perl 5.22 導入了 B::PADNAMELIST 和 B::PADNAME 類別。
一個 pad 的清單。第一個是包含名稱的 B::PADNAMELIST。其餘目前是 B::AV 物件,但這可能會在未來的版本中改變。
類似於 ARRAY
,但會取得一個索引作為引數,以取得只有一個元素,而不是所有元素的清單。
這個在 5.22 中導入的方法傳回 B::PADNAMELIST。它等於帶有 0 參數的 ARRAYelt
。
這個在 5.22 中導入的方法傳回同一個 padlist 的複製所共用的 ID。
這個方法也在 5.22 中新增,傳回外部 padlist 的 ID。
為了向後相容,如果 PADNAMEt_OUTER 旗標已設定,FLAGS 方法也會新增 SVf_FAKE 旗標。
代表已鍵入詞彙的儲存空間的 B::HV 物件。
TYPE 的向後相容別名。
代表「our」變數的儲存空間的 B::HV 物件。
「my」子例程的原型 CV。
代表詞彙可見範圍的序列號碼。如果 PADNAMEt_OUTER 已設定,則沒有意義。
只有在 PADNAMEt_OUTER 已設定時才有意義。
只有在 PADNAMEt_OUTER 已設定時才有意義。
傳回布林值,檢查 padname 是否為 PL_padname_undef。
雖然 optree 是唯讀的,但有一個覆寫功能,讓你可以覆寫 B::*OP 方法為特定 op 傳回的各種值。$B::overlay
應該設定為參考一個兩層深的雜湊:由 OP 位址索引,然後是方法名稱。每當呼叫一個 op 方法時,如果雜湊中存在值,則會傳回該值。此功能由 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,mbeattie@sable.ox.ac.uk