《手寫PHP編譯器》之實現echo_expr
阿新 • • 發佈:2021-08-08
到目前為止,我們已經實現了yaphp原始碼到AST的生成工作。但是,我們對echo語句的實現還是簡單處理了,之前的實現如下:
statement:
T_ECHO expr ';' { $$ = $2; }
;
可以看到,這裡實際上我們沒有體現出T_ECHO的功能,我們僅僅處理了expr。所以,這裡我們需要去處理一下。
有了前面的基礎之後,我們可以非常輕鬆的來實現這個AST的生成。
我們修改後的規則如下:
statement: T_ECHO echo_expr ';' { $$ = $2; } ; echo_expr: expr { std::cout << "create echo zend_ast" << std::endl; $$ = zend_ast_create_1(ZEND_AST_ECHO, 0, $1); } ;
可以看到,我們加了一個echo_expr
,用來建立一個ZEND_AST_ECHO
型別的AST。這裡,我們的語法和php-src的有點不同,php-src的語法功能更加的豐富一點,它支援echo
後面跟一個ZEND_AST_STMT_LIST
,這個的實現也是比較簡單的,和我們之前建立top_statement_list
的思路是一致的。這裡小夥伴們可以自己去實現一下,我們的yaphp就不支援這種可有可無的語法了。
其中,zend_ast_create_1
的實現如下:
zend_ast *zend_ast_create_1(zend_ast_kind kind, zend_ast_attr attr, zend_ast *child) { zend_ast *ast; ast = (zend_ast *) malloc(zend_ast_size(1)); ast->kind = kind; ast->attr = attr; ast->child[0] = child; return ast; }
然後,我們需要在_zend_ast_kind
中增加一個ZEND_AST_ECHO
:
/* 1 child node */
ZEND_AST_ECHO,
最後,我們再修改一下我們的dump_compiler_globals函式:
else if (ast->kind > ZEND_AST_0_NODE_END && ast->kind < ZEND_AST_1_NODE_END) { queue.push_back(ast->child[0]); } else if (ast->kind > ZEND_AST_1_NODE_END && ast->kind < ZEND_AST_2_NODE_END) { queue.push_back(ast->child[0]); queue.push_back(ast->child[1]); }
其中,ZEND_AST_0_NODE_END
, ZEND_AST_1_NODE_END
, ZEND_AST_2_NODE_END
這三個zend_ast
節點型別php-src是沒有的,這裡是為了方便除錯給加上的,否則,我們每次增加一個zend_ast
節點型別,就需要寫一個if語句。
現在,讓我們來編譯一下yaphp,並且執行,結果如下:
create * zend_ast
create + zend_ast
create echo zend_ast
kind: 129, attr: 0
kind: 131, attr: 0
kind: 515, attr: 1
kind: 65, attr: 0, value: 1
kind: 515, attr: 3
kind: 65, attr: 0, value: 2
kind: 65, attr: 0, value: 3
符合我們的預期。