Erlang Abstract Form--產生和擷取
Smerl通過修改Erlang的內部解析樹,並重新編譯這棵解析樹實現meta programming。為了理解Smerl,我們首先需要理解Erlang內部解析樹的產生、表達形式和擷取、修改的方法。
Erlang把解析樹稱為Abstract Form,要獲得某一個模組的AbstractForm有兩種方法:
* 從已經編譯的beam檔案中擷取Abstract Form
* 直接解析原始碼產生Abstract Form
在一個實際啟動並執行程式中,我們可能無法存取原始碼,即使能夠獲得原始碼,它也不一定完全和正在啟動並執行beam檔案同步。因此,讓我們首先把精力放在第一種方法上,第二種方法將在後面需要的時候描述。實際上兩種方法只是在獲得AbstractForm的方法上有所不同,而對Abstract Form的理解和操縱是完全一樣的。
beam_lib 提供了操作beam檔案所需要的介面。Erlang的beam檔案格式是 "EA IFF 1985"標準的一個變種,它把資料分為多個 chunks. Chunk資料可以是二進位或者複合的term。如果通過名字(erlang的atom)去引用chunk,那麼將返回複合term,當然這是我們需要的。
擷取chunk的函數是beam_lib:chunks,例如
beam_lib:chunks(Beam,[abstract_code])
將返回Beam變數所指定的beam檔案中包含的abstract_code,也就是我們需要的Abstract Form。當然,除了abstract_code以外,chunks函數還可以用來獲得以下的各種調試資訊:
* abstract_code ("Abst")
* attributes ("Attr")
* compile_info ("CInf")
* exports ("ExpT")
* labeled_exports ("ExpT")
* imports ("ImpT")
* indexed_imports ("ImpT")
* locals ("LocT")
* labeled_locals ("LocT")
* atoms ("Atom")
這裡有兩點需要注意。
首先,我們前面說用atom去引用將獲得複合term,如果用字串去引用,chunks函數返回位元據。上面的列表中,每一項你都可以用兩種方法去擷取(括弧外和括弧內)。例如可以用abstract_code這個atom去獲得複合term,也可以用括弧中的"Abst"去擷取位元據。
另外,我們說chunks函數用來獲得beam檔案中的調試資訊。這意味著我們必須在編譯的時候使用調試選項。
Erlang的compile可以用debug_info選項:
debug_info
Include debug information in the form of abstract code (see The Abstract Format in ERTS User's Guide) in the compiled beam module. Tools such as Debugger, Xref and Cover require the debug information to be included.
Warning: Source code can be reconstructed from the debug information. Use encrypted debug information (see below) to prevent this.
See beam_lib(3) for details.
如果使用debug_info選項,那麼編譯得到的beam檔案內部將以abstract code的形式儲存調試資訊。但是警告也說明,如果使用該選項,那麼其他人就可以從這些資訊重建原始碼。好在compile還提供了一種加密方法,你在編譯的時候提供一個key,那麼這些調試資訊必須在提供同樣key的時候才能解密獲得。
現在,我們嘗試一個最簡單的模組來驗證上面的理解。建立一個空的module simplest,內容如下:
module(simplest).
%%
%% Include files
%%
%%
%% Exported Functions
%%
-export([]).
首先,我們沒有使用debug_info選項編譯:
erl
Erlang (BEAM) emulator version 5.5 [source] [async-threads:0]
Eshell V5.5 (abort with ^G)
1> c(simplest).
{ok,simplest}
2> beam_lib:chunks(simplest,[abstract_code]).
{ok,{simplest,[{abstract_code,no_abstract_code}]}}
3>
shell返回的結果中no_abstract_code表示simplest這個beam檔案中並沒有包含任何abstract code。接著我們用debug_info選項重新編譯:
3> c(simplest,[debug_info]).
{ok,simplest}
4> beam_lib:chunks(simplest,[abstract_code]).
{ok,{simplest,[{abstract_code,{raw_abstract_v1,
[{attribute,1,file,{"./simplest.erl",1}},
{attribute,4,module,simplest},
{attribute,13,export,[]},
{eof,25}]}}]}}
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/minyskirt/archive/2009/12/12/4991521.aspx