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 是目标文件应该是

发布了93 篇原创文章 · 获赞 2 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_32783703/article/details/103947634