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 是一个扫描器。可以很高效的产生代码
在我们安装号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 是目标文件应该是