zend虛擬機的學習(一)

Zend虛擬機部分的學習

學習自網址:
http://www.php-internals.com/book/?p=chapt07/07-01-zend-vm-overview

我之前也是一直非常奇怪php是如何把php編譯成機械碼的,2年前看zend虛擬機的文章雲山霧繞,這一次又開始看zend虛擬機是如何實現的,tipi比較老了,但是還是在一些方面很具有借鑑經驗,因爲畢竟php根還在那裏,不可能連根拔起

這一段引自tipi

爲了方便讀者對Zend引擎的實現有個全面的感覺,下面列出涉及到Zend引擎實現的核心代碼文件功能參考。

Zend引擎的核心文件都在$PHP_SRC/Zend/目錄下面。不過最爲核心的文件只有如下幾個:

PHP語法實現
Zend/zend_language_scanner.l
Zend/zend_language_parser.y
Opcode編譯
Zend/zend_compile.c
執行引擎
Zend/zend_vm_*
Zend/zend_execute.c

我們知道計算機其實gcc或者g++只認識c或者c++,c c++代碼又轉化爲彙編最後變爲了二進制機器碼作爲電腦程序執行,那麼他是怎麼把我們的php代碼轉化成c或者c++的呢?

其實自己寫的話真是一個十分複雜的東西,因爲c語言對字符串的處理比較弱。。至少我是這麼認爲的,php我認爲比較舒服的就是他有良好的api對字符串進行處理。

php詞法分析使用的是re2c,

re2c 是一個掃描器。可以很高效的產生代碼

官網:http://re2c.org/

在我們安裝號re2c之後

這個文件我是demo.l

#include <stdio.h>

char *scan(char *p){
#define YYCTYPE char
#define YYCURSOR p
#define YYLIMIT p
#define YYMARKER q
#define YYFILL(n)
    /*!re2c
      [0-9]+ {return "number";}
      [a-z]+ {return "lower";}
      [A-Z]+ {return "upper";}
      [^] {return "unkown";}
     */
}

int main(int argc, char* argv[])
{
    printf("%s\n", scan(argv[1]));

    return 0;
}

使用re2c把demo.l轉化爲demo.c

運行結果

/* Generated by re2c 0.13.4 on Sun Jan 12 16:37:54 2020 */
#line 1 "demo.l"
#include <stdio.h>

char *scan(char *p){
#define YYCTYPE char
#define YYCURSOR p
#define YYLIMIT p
#define YYMARKER q
#define YYFILL(n)

#line 13 "demo.c"
{
    YYCTYPE yych;

    if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
    yych = *YYCURSOR;
    switch (yych) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':   goto yy2;
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
    case 'G':
    case 'H':
    case 'I':
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'S':
    case 'T':
    case 'U':
    case 'V':
    case 'W':
    case 'X':
    case 'Y':
    case 'Z':   goto yy6;
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
    case 'i':
    case 'j':
    case 'k':
    case 'l':
    case 'm':
    case 'n':
    case 'o':
    case 'p':
    case 'q':
    case 'r':
    case 's':
    case 't':
    case 'u':
    case 'v':
    case 'w':
    case 'x':
    case 'y':
    case 'z':   goto yy4;
    default:    goto yy8;
    }
yy2:
    ++YYCURSOR;
    yych = *YYCURSOR;
    goto yy15;
yy3:
#line 10 "demo.l"
    {return "number";}
#line 91 "demo.c"
yy4:
    ++YYCURSOR;
    yych = *YYCURSOR;
    goto yy13;
yy5:
#line 11 "demo.l"
    {return "lower";}
#line 99 "demo.c"
yy6:
    ++YYCURSOR;
    yych = *YYCURSOR;
    goto yy11;
yy7:
#line 12 "demo.l"
    {return "upper";}
#line 107 "demo.c"
yy8:
    ++YYCURSOR;
#line 13 "demo.l"
    {return "unkown";}
#line 112 "demo.c"
yy10:
    ++YYCURSOR;
    if (YYLIMIT <= YYCURSOR) YYFILL(1);
    yych = *YYCURSOR;
yy11:
    switch (yych) {
    case 'A':
    case 'B':
    case 'C':
    case 'D':
    case 'E':
    case 'F':
    case 'G':
    case 'H':
    case 'I':
    case 'J':
    case 'K':
    case 'L':
    case 'M':
    case 'N':
    case 'O':
    case 'P':
    case 'Q':
    case 'R':
    case 'S':
    case 'T':
    case 'U':
    case 'V':
    case 'W':
    case 'X':
    case 'Y':
    case 'Z':   goto yy10;
    default:    goto yy7;
    }
yy12:
    ++YYCURSOR;
    if (YYLIMIT <= YYCURSOR) YYFILL(1);
    yych = *YYCURSOR;
yy13:
    switch (yych) {
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
    case 'i':
    case 'j':
    case 'k':
    case 'l':
    case 'm':
    case 'n':
    case 'o':
    case 'p':
    case 'q':
    case 'r':
    case 's':
    case 't':
    case 'u':
    case 'v':
    case 'w':
    case 'x':
    case 'y':
    case 'z':   goto yy12;
    default:    goto yy5;
    }
yy14:
    ++YYCURSOR;
    if (YYLIMIT <= YYCURSOR) YYFILL(1);
    yych = *YYCURSOR;
yy15:
    switch (yych) {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':   goto yy14;
    default:    goto yy3;
    }
}
#line 14 "demo.l"

}

int main(int argc, char* argv[])
{
    printf("%s\n", scan(argv[1]));

    return 0;
}

php中zend_language_scanner.l這個就是re2c的規則文件
安裝步驟

autoreconf
./configure
make
sudo make install

php的語法解析文件 zend_language_scanner.l ,我們可以使用下面這個命令來生成

re2c -F -c -o zend_language_scanner2.c zend_language_scanner.l

-F 是flex語法

-c 是條件

-o 是目標文件應該是

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章