PHP引擎实现(二)

上一次说到Zend的词法分析,现在该轮到语法分析和中间代码生成部分了。一般情况下,词法分析和语法分析是在一起的过程,所以一般词法分析器和语法分析器是交织在一起的,共同运行。
PHP的语法分析器使用的是Bison。具体的语法分析器定义在 Zend/zend_language_parser.y文件中。

在文件中,我们可以比较容易的找到针对 T_ECHO的语法规则:

...
    |   T_ECHO echo_expr_list ';'
...

即必须满足T_ECHO + 一个echo_expr_list,后面加;的语法,如果不满足,则直接就会报错了。我们还能继续找到echo_expr_list的定义:

echo_expr_list:
        echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
    |   expr                    { zend_do_echo(&$1 TSRMLS_CC); }
;

这里我们看到了一个递归的定义,即一个 echo_expr_list 可以包含一个 echo_expr_list + , + expr(表达式) 或者直接就是一个expr(表达式),当只有一个表达式时,就直接调用zend_do_echo(),并将第一个参数(也就是expr的值)传给该函数,如果是递归的,也是一样,先递归调用,然后再将第三个参数也是就是,后面的expr传给zend_do_echo()

在Bison中,$$代表规则的结果,$1代表规则的第一个值,$2代表第二个,依次类推。

下面很自然的就要开始看一下 zend_do_echo()这个函数是干什么的了,这个函数的实现在Zend/zend_compile.c文件中:

void zend_do_echo(const znode *arg TSRMLS_DC) /* {{{ */
{
	zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

	opline->opcode = ZEND_ECHO;
	SET_NODE(opline->op1, arg);
	SET_UNUSED(opline->op2);
}
/* }}} */

这个函数很简单,首先,从CG(active_op_array)中找到下一个opline,然后将这个OP的opcode设置为ZEND_ECHO,opline的第一个参数设置为传入的arg,设置第二个参数为UNUSED,也就是说,ZEND_ECHO这个OP,实际执行的时候,只会用到一个参数。

到目前为止。PHP编译部分算是基本理清了,语法分析器和词法分析器互相配合,从第一行开始,不断地将代码转化为一个个的opline存到CG(active_op_array)中,等到编译完成,再从CG(active_op_array)中一个个取出OP,然后执行。对应到实际的计算机,编译完成后的CG(active_op_array)就好比是内存中的代码段,在执行中也有个类似PC寄存器的指针指向这个代码段,然后不停的执行当前的OP,直到所有的OP全部执行完成推出。当然执行部分,是下面要说的东西了。

现在在回头看一下上篇说的那个例子:

<?php
    echo 'Hello ' . 'World';
    echo 'Hello ', 'World';
?>

编译后的结果。

line   #* E I O op    fetch  ext  return  operands
---------------------------------------------------------
2   0  E >   CONCAT               ~0      'Hello+', 'World'
    1        ECHO                         ~0
3   2        ECHO                         'Hello+'
    3        ECHO                         'World'
5   4      > RETURN                       1

同样是echo,当由,分隔的两个expr时,生成了2个ECHO OP,而中间用.操作符连接的两个字符串,是先通过CONCAT连接后,再调用一次ECHO输出,最后,调用RETURN 返回返回值。

参考:

  1. http://www.php-internals.com/book/
  2. http://www.gnu.org/software/bison/manual/html_node/Action-Features.html#Action-Features