Provided by: manpages-zh_1.5-1_all bug

NAME

       perlcompile - 關於 Perl 編譯器和翻譯器的介紹

DESCRIPTIONyz
       Perl 一直是有一-
       蚑s譯器的:你的源檔案會被編譯成一種內部格式(一種語法分析樹),並且在運行前還會被優化。從5.005版本起,Perl
       在發行時就帶有一-
       蚍珔竷i以檢查優化過的語法分析樹(該模塊稱作B模塊("B")),它被用來編寫許多有用的功能,包括一-
       茈i以將你的Perl轉成C鴝l碼的模塊,這樣再編譯後就可以得到一-
       茈i執行的檔案了。

       "B" 模塊提供了訪問語法分析樹的方法, 其它的一些模塊(「後端」)則對這-
       蚞蘤i行操作。一些把它(語法樹)以字節碼的形式輸出,還有以C-
       鴝l碼形式的輸出的,後者以半可讀的文本形式輸出的。另一些遍歷整棵語法樹以建立一-
       蚚鰫顝狳洏峈漱l程式,格式及變量的交叉引用表。還有另外一些檢查你的代碼,看看有沒有模棱兩可的構造。另一些則-
       奐s將語法樹導出成Perl代碼,可以起代碼美化或是消除混亂的代碼的作用。

       因為 "B"
       模塊的最初目的是提供一種能將Perl程式轉為對應C代碼的方法,接著就能把它變成可執行檔案了,所以
       "B" 模塊和它的那些後端模塊就被認為是「編譯器」了,即使它-
       拊篕琱W沒有做任何編譯方悸漕C這蚑s譯器的各茬﹞擎踳T的說應該是-
       荂u翻譯器」,或者一荂u檢視器」,但是用Perl的人抪Qn一-
       荂u編譯選項」而不是一茈s做「檢視器」的小玩藝。你能怎麼辦呢?

       這篇文章的主n內容是講Perl編譯器的用法:它包含的模塊,怎樣使用那些最-
       n的後端模塊,它怞酗偵繵暋D,如何讓它怳u作。

       Layout局

       編譯器的後端放在 "B::" 裏情A而前端(就是你,編譯器的使用者,有時-
       n與之交互的)是 O 模塊。一些後端(如
       "B::C"))提供了一些程式(如perlcc)來隱藏模塊的復雜性。

       這裏是一些o知道的南後端,並附有它-
       怚堳e的狀態,用0到10的整數表示。(狀態0表示目前該部分功能只是有一-
       荇堿[,還沒有實現;狀態10則表示如果還有Bug的話,我抪|感到很奇怪的):

       B::Bytecode
           將語法樹存成機器相關的格式,可供BtyeLoader模塊可以在以後-
           奐s裝入。狀態:5(一些部分可以工作,一些不可以,還有一些還沒有測試)

       B::C
           創建C代碼檔案,其中包括了-
           垂婸y法樹和恢復解釋器的代碼。狀態:6(許多情況下可以正常工作,包括使用了Tk的程式)。

       B::CC
           按照語法樹中運行期代碼的路徑創建C代碼檔案。這是最像 Perl - C
           翻譯器的一-
           荂A但是它生成的代碼幾乎是不能看懂的,因為它把語法樹翻譯成了一-
           茈角j的switch結構來操作Perl中的結構。最終的目的是在perl程式中給出足夠的類型信息後,可以將
           perl 數據結構的操作轉換為 c 級別的數據結構,對 int 和 float
           的操作。狀態:5 (有些可以工作,包括不復雜的 Tk 示例).

       B::Lint
           當發現你的代碼中有模棱兩可的構造時會發出警告。狀態:6(許多情況下可以正常工作,僅僅在很少數的領域內它會停止工作)。

       B::Deparse
           奐s生成Perl代碼,試著把代碼用一-
           P的格式寫出來。狀態:8(它工作得很好,只是會略去一些晦澀難懂的部分)。

       B::Xref
           生成關於申明和關於變量以及子程式的使用情況的報告。狀態:8(它工作得很好,只是仍有一點延遲方-
           悸槓ugs)。

Using The Back Ends端
       接下來的部分介紹怎樣使用各種各樣的編譯器後端。介紹的順序按照後端的成熟程度排列,所以最為-
       定的,經過了驗証的後端會最先介紹,還在試驗中和沒有完成的後端就放到後-
       探yz了。

       O模塊預設讓 -c
       開關有效,這防止Perl在編譯完代碼後運行程式。這也是為什麼所有的後端在產生任何輸出前都會列印一句:

         myperlprogram syntax OK

       The Cross Referencing Back Ende端

       交叉引用後端(B::Xref)生成一蚚鰫顜A的程式的報表,把各-
       茈茤以及子程式,變量(包括格式)的使用情況存入檔案中去。舉例來說,這有一段摘自對pod2man程式分析後生成的報表(該程式是Perl自帶的一-
       茖珛{):

         Subroutine clear_noremap
           Package (lexical)
             $ready_to_print   i1069, 1079
           Package main
             $&                1086
             $.                1086
             $0                1086
             $1                1087
             $2                1085, 1085
             $3                1085, 1085
             $ARGV             1086
             %HTML_Escapes     1085, 1085

       這裏展示了"clear_noremap" 子程式中變量的使用情況。就像變量
       $ready_to_print 是 my() (詞法) 的一蚥僆q,在第1069行被引入(
       鴗憟峈熊是introduced,也就是在 my() 中第一次被定義的意思
       ),然後在第1079行該變量被使用了。從主包(main package)中來的變量 $&
       又在第1086行被使用, 等等。

       行號前悼i能會有一茼r母作為前綴,它怐熒N思是:

       i   變量漲董Q引入 (在my()中申明) 。

       &   子程式或者方法的引用。

       s   定義的子程式。

       r   定義的格式。

       交叉引用中最為有用的選項就是把報表存入不同的檔案,例如n把關於
       myperlprogram 的報表存入檔案 report 中:

         $ perl -MO=Xref,-oreport myperlprogram

       The Decompiling Back Ends端

       反編譯後端將把你的Perl語法樹奐s變成鴝l碼。生成的-
       鴝l碼會按照某種格式組織,所以這-
       茷廕搘i以用來消除代碼中的混亂部分。此後端的基本使用方法如下:

         $ perl -MO=Deparse myperlprogram

       你也許馬上會發現Perl並不知道如何給你的代碼分段。你-
       n自己手動添入新行來把這大斷的代碼分開。然而現在,讓我-
       怓搰搘N碼只有一行時情況怎樣,這茷廕揧|做些什麼:

         $ perl -MO=Deparse -e '$op=shift||die "usage: $0
         code [...]";chomp(@ARGV=<>)unless@ARGV; for(@ARGV){$was=$_;eval$op;
         die$@ if$@; rename$was,$_ unless$was eq $_}'
         -e syntax OK
         $op = shift @ARGV || die("usage: $0 code [...]");
         chomp(@ARGV = <ARGV>) unless @ARGV;
         foreach $_ (@ARGV) {
             $was = $_;
             eval $op;
             die $@ if $@;
             rename $was, $_ unless $was eq $_;
         }

       這-
       茷廕搕]有幾條選項控制生成的代碼,舉例說,你可以把縮進的尺寸設在4(最大)到2之間:

         $ perl -MO=Deparse,-si2 myperlprogram

       -p 開關控制在常常可以不加圓括號的地方加上它怴G

         $ perl -MO=Deparse -e 'print "Hello, world\n"'
         -e syntax OK
         print "Hello, world\n";
         $ perl -MO=Deparse,-p -e 'print "Hello, world\n"'
         -e syntax OK
         print("Hello, world\n");

       n知道更多,請參考 B::Deparse

       Lint端

       lint 後端 (B::Lint) 檢察程式中不好的程式榆獢C一茧{式認為的不好-
       榆璆i能對另外一茧{式來說是用起來很有效的工具,所以有選項讓你設定-
       些東東將會受到檢查。

       n運行一虓格檢查器檢察你的代碼:

         $ perl -MO=Lint myperlprogram

       n取消對上下文和沒有定義的子程式的檢查:

         $ perl -MO=Lint,-context,-undefined-subs myperlprogram

       n知道更多的選項信息,請看 B::Lint

       The Simple C Back EndC端

       這蚍珔竷峔荍漰A的Perl程式的內部編譯狀態存儲到一-
       笏代碼檔案中去,而生成的C代碼就可以被特定孕x上的C編譯器轉換成一-
       茈i執行檔案了。最後的程式還會和Perl解釋器的庫檔案靜態鏈接起來,所以它不會節省你的磁碟空間(除非你的Perl是用共享的庫檔案創建的)或是程式大小,然而,另一方-
       情A程式啟動起來會快一些。

       "perlcc" 工具預設是生成以下的可執行檔案。

         perlcc myperlprogram.pl

       The Bytecode Back Endr`X端

       這-
       蚍珔竷u有在你能夠找到一種方法來裝入並運行它生成的字節碼時才會顯得有用。ByteLoader模塊提供了這項功能。

       n把Perl轉換成可執行的字節碼,你可以使用 "perlcc" 的 "-B" 開關:

         perlcc -B myperlprogram.pl

       字節碼是和機器類型無關的,所以一旦你編譯了一-
       蚍珔籇峎O程式,它就可以像Perl鴝l碼一樣具有可移植性。(假設那-
       蚍珔籇峈拑{式的使用者有一茖為鷛s的Perl解釋器來對字節碼進行解碼)

       有一些選項用來控制n生成的字節碼的性質和關於優化方悸滌捊A-
       n知道這些選項的詳細情況,請參考 B::Bytecode

       The Optimized C Back EnduC端

       優化的C後端按照語法樹中運行期代碼的路徑將你的Perl程式轉換成等效的(但是被優化了的)C代碼檔案。這-
       笏程式會直接對Perl的數據結構進行操作,而且也會鏈接Perl的解釋器的庫檔案,以支持
       eval(), "s///e", "require"  等等。

       "perlcc" 工具使用 -O 開關生成這種可執行檔案。n編譯一紞erl程式(以".pl"
       或者".p" 結尾):

         perlcc -O myperlprogram.pl

       從Perl模塊創建一茼@享庫檔案(以 ".pm" 結尾):

         perlcc -O Myperlmodule.pm

       知道更多,請參考 perlcc 和 B::CC.

Module List for the Compiler SuitesMC表
       B   這蚍珔繻O一-
           茼菗椌滿]introspective,用Java的術語說就是「reflective」)模塊,允許Perl程式審視自己的內部。後端模塊都是通過這-
           蚍珔籊茬X問語法分析樹的。而你,後端模塊的使用者,就不用和B模塊打交道了。

       O   這蚍珔繻O編譯器的那些後端的前端,一般像這樣進行調用:

             $ perl -MO=Deparse myperlprogram

           這與在這紞erl程式中使用 "use O 'Deparse'" 相同。

       B::Asmdata
           這蚍珔臛Q B::Assembler 模塊使用,而 B::Assembler 又接著被
           B::Bytecode 模塊使用,B::Bytecode中有一-
           茼r節碼形式存放的語法分析樹以便以後裝入。B::Asmdata自己並不算是一-
           茷廕搳A也許說它是後端的一茞掍韝騆好。

       B::Assembler
           這蚍珔竷i以將語法樹轉為適合存儲和恢復的數據形式。它本角ㄛO一-
           茷廕搳A但是算是某茷廕搌漱@茞掍鞳C assemble  程式用它來生成字節碼。

       B::Bblock
           這蚍珔臛Q B::CC 後端使用。它被用來運行「基本塊」。一-
           荌禰辣臙N是一段從頭到尾的操作,中間是不可能停下來或出現分支的。

       B::Bytecode
           這-
           蚍珔竷i以由程式的語法樹生成字節碼。生成的字節碼會被寫入到檔案中,以後還能被-
           奐s恢復成語法樹。總的目標就是為了只進行一次費時的程式編譯工作,然後把解釋器的狀態存入檔案中,運行程式時再把狀態從檔案中恢復。
           具體的用法請參考 "The Bytecode Back End" 。

       B::C
           這-
           蚍珔糮鷊蚖y法樹和其他一些解釋器的內部數據結構生成C代碼。然後你再編譯生成的C代碼,就可以得到一-
           茈i執行檔案了。運行時這-
           茈i執行檔案會恢復解釋器和內部的數據結構來轉動程式。n知道細節請參考
           "The Simple C Back End"。

       B::CC
           這蚍珔糮鷊荍A程式中的操作生成C代碼。不像 B::C
           模塊只是把解釋和它的狀態存入C程式中, B::CC
           模塊生成的是不包含解釋器的C 程式,所以用 B::CC 翻譯的C
           程式運行速度比一般的解釋執行的程式速度n快,具體用法請參考 "The
           Optimized C Back End" 。

       B::Concise
           這蚍珔蘄擖X一蚋票銂 (但是完整的) Perl 分析樹。它的輸出比 B::Terse
           或者 B::Debug 的結果更容易定制 (並且也可以模仿它)。這-
           蚍珔藿黈捊g自己的後端,或者學習 Perl 實現的人有用。它對一般的程式-
           沒有用處。

       B::Debug
           這-
           蚍珔籈榽erl語法分析樹非常詳細地輸出到標準輸出上去。這對正在編寫自己的後端程式,或正在深入Perl內部機制的人-
           怢蚖′O非常有用的。對普通程式來說則沒什麼用。

       B::Deparse
           這蚍珔翿N編譯了的語法樹反向分析得出Perl-
           鴝l碼,這在調試或是反編譯他人代碼的時-
           埸|是非常有用的。另外讓它為你自己的代碼做一些美化工作也是可以的。-
           n知道細節請參考 "The Decompiling Back End"。

       B::Disassembler
           這蚍珔籈潀r節碼恢復成語法樹,它本角ㄛO一茷廕搳A而是某茷廕搌漱@-
           茞掍鞳C它會被和字節碼在一起的 disassemble 程式使用。

       B::Lint
           這-
           蚍珔蘛f視你的代碼編譯後的格式,並且找到那些容易讓人皺眉,卻又不至於引起警告的地方。舉例來說,使用一-
           蚍迠q內容(scalar context)的數組,而不顯式地申明成
           "scalar(@array)" 。這種情況是會被 Lint 標示出來的。n知道細節請參考
           "The Lint Back End"。

       B::Showlex
           這蚍珔籉C印出 my()
           中的變量在函數或是檔案中的使用情況,以得到一份關於 my()
           中的變量在定義於檔案 myperlprogram 中的子程式 mysub()
           中的使用情況的列表:

             $ perl -MO=Showlex,mysub myperlprogram

           n得到一份關於 my() 中的變量在檔案myperlprogram中的使用情況的列表:

             $ perl -MO=Showlex myperlprogram

           [BROKEN]

       B::Stackobj
           這蚍珔臛Q B::CC 模塊調用。它本角ㄛO後端,但是是某茷廕搌漱@茞掍鞳C

       B::Stash
           這蚍珔臛Q perlcc  程式調用,而perlcc可以把一-
           蚍珔蘀s譯成可執行檔案。B::Stash
           把程式使用的符號表列印出來,並被用來阻止 B::CC 為 B::* 或是 O
           模塊生成C 代碼。它本角ㄛO後端,但是是某茷廕搌漱@茞掍鞳C

       B::Terse
           這-
           蚍珔竷峔茼C印語法樹的內容,但是信息不會有B::Debug列印的那麼多。對比來說,"print
           "Hello, world."" 會讓 B::Debug 產生96行輸出, 但是
           B::Terse只會有6行。

           這蚍珔藿鴷縝b編寫自己的後端程式,或正在深入Perl內部機制的人-
           怢蚖′O非常有用的。對普通程式來說則沒什麼用。

       B::Xref
           這蚍珔籉C印一茬曭磽C出在程式中裏定義和使用了-
           些變量,子程式或格式,報表還會列出程式裝入的模塊。-
           n知道詳細的使用方法,請參考 "The Cross Referencing Back End" 。

KNOWN PROBLEMSwD
       簡單 C 後端目前只保存以字符和數字命名的類型說明

       優化的 C 後端會為一些不該為之輸出的模塊(比如說
       DirHandle)輸出代碼。而且它不太可能正確地處理正在執行的子程式外部的goto語句(goto
       &sub is OK)。目前 "goto LABEL" 語句在這-
       茷廕搕之馴不會工作。他還會生成讓C
       編譯器頭痛無比的巨大的初始化函數。如果把這-
       茠鴝l化函數分割開是能得到比目前更好的效果的。另外的問題包括:處理無符號的數學問題時不能正確工作;一些操作碼如果按照預設的操作碼機制處理也會有非正常的結果。

       BEGIN{} 塊會在編譯你的代碼的時堀Q執行。所有的在BEGIN{}
       中初始化的外部狀態,如打開的檔案,初始的數據庫連結等等,會有不正確的表現。為了解決這-
       荌暋D,Perl中又提供了一 INIT{} 塊來對應程式編譯之後,正式運行之前-
       n執行的那段代碼。執行的順序是:BEGIN{},
       (後端編譯程式可能這時會保存狀態), INIT{}, 程式運行, END{}。

AUTHOR@者
       這篇文章最初是由 Nathan Torkington
       編寫,現在由郵件列表(perl5-porters@perl.org.)維護

者
      U(sunny65535) <sunny65535@263.net>