編譯到PHP中
但是由於各種原因
寫這篇文章一是因為這方面資料太少
那對PHP源碼的研究會更上一層樓地 ^
我盡可能寫的通俗易懂些
這個項目思路源於facebook的開源項目 HipHop
其實我對這個項目的性能提高
於HipHop
PHPtoc
它的流程如下
進入正題
這裡最難的就是語法分析器了
所以
如果要用PHP的語法分析器就不太現實了
所以決定重新寫一套自己的語法分析規則
re
成我們自己的程序
件
注
re
我們寫的規則
我們寫的(f)lex語法規則
會通過 yacc/bison編譯成一個parse
比如我們PHP代碼是
掃描其中有一個規則
return T_ECHO;
}
掃描器函數scan會拿到
parse
下面會具體的說一說
感興趣的可以去看看
還麼有結束
re
接口代碼
不像其他的掃描器程序
YYCONDTYPE
用
YYCTYPE
用來維持一個輸入符號
YYCTXMARKER
*YYCTYPE類型的表達式
YYCURSOR
*YYCTYPE類型的表達式指針指向當前輸入的符號
YYDEBUG(state
這個只有指定
這個函數應該有以下簽名
YYFILL(n)
當緩沖器需要填充的時候
YYGETCONDITION()
如果使用了
YYGETSTATE()
如果
YYLIMIT
表達式的類型 *YYCTYPE 標記緩沖器的結尾(YYLIMIT(
YYSETCONDITION(c)
這個宏用來在轉換規則中設置條件
YYSETSTATE(s)
用戶只需要在指定
YYMARKER
類型為*YYCTYPE的表達式
掃描器
掃描器文件結構
/* #include 文件*/
/*宏定義*/
//掃描函數
int scan(char *p){
/*掃描器規則區*/
}
//執行scan掃描函數
int yylex(){
int token;
char *p=YYCURSOR;//YYCURSOR是一個指針
while(token=scan(p)){//這裡會移動指針p
return token;
}
}
int main(int argc
BEGIN(INITIAL);//
YYCURSOR=argv[
yyparse();
}
BEGIN 是定義的宏
#define YYCTYPE char //輸入符號的類型
#define STATE(name) yyc##name
#define BEGIN(n) YYSETCONDITION(STATE(n))
#define LANG_SCNG(v) (sc_globals
#define SCNG LANG_SCNG
#define YYGETCONDITION() SCNG(yy_state)
#define YYSETCONDITION(s) SCNG(yy_state)=s
yyparse函數是在yacc 中定義的
裡面有一個關鍵宏
#define YYLEX yylex()
它會執行scaner掃描器的yylex
可能會有點繞
在scanner
將掃描器返回的
token返回給parse
舉例
scanner
#include
#include
int scan(char *p){
/*!re
<INITIAL>
BEGIN(ST_IN_SCRIPTING);
return T_OPEN_TAG;
}
return T_ECHO;
}
[
return T_LNUMBER;
}
*/
}
int yylex(){
int c;
// return T_STRING;
int token;
char *p=YYCURSOR;
while(token=scan(p)){
return token;
}
}
int main (int argc
BEGIN(INITIAL);//初始化
YYCURSOR=argv[
yyparse();//yyparse()
return
}
這樣一個簡單的掃描器就做成了
解析器我用的是flex和bison
關於flex的文件結構
%{
/*
C代碼段將逐字拷貝到lex編譯後產生的C源文件中
可以定義一些全局變量
*/
#include
#include
extern int yylex();//它在scanner
void yyerror(char *);
# define YYPARSE_PARAM tsrm_ls
# define YYLEX_PARAM tsrm_ls
%}
{定義段
//這就是關鍵 token程序是根據這是做switch的
%token T_OPEN_TAG
%token T_ECHO
%token T_LNUMBER
%%
{規則段}
start:
T_OPEN_TAG{printf(
|start statement
;
statement:
T_ECHO expr {printf(
;
expr:
T_LNUMBER {$$=$
%%
{用戶代碼段}
void yyerror(char *msg){
printf(
}
在規則段中
在scanner
yyparse會根據scan返回的標記做switch
它會通過宏 #line 映射到 parse
那
為了能直觀一些
這個時候yychar是
繼續
YYTRANSLATE宏接受yychar
#define YYTRANSLATE(YYX) /
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
/* YYTRANSLATE[YYLEX]
static const yytype_uint
{
};
yyparse拿到這個值
bison會生成很多用來映射的數組
這樣bison就能找到token所對應的代碼
switch (yyn)
{
case
/* Line
#line
{printf(
break;
這樣
From:http://tw.wingwit.com/Article/program/PHP/201311/20842.html