📄 php_syntree.cpp
字号:
//// This file is part of the aMule Project.//// Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )// Copyright (C) 2005-2008 Froenchenko Leonid ( lfroen@amule.org )//// Any parts of this program derived from the xMule, lMule or eMule project,// or contributed by third-party developers are copyrighted by their// respective authors.//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// // You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA//#include <string> // Do_not_auto_remove (g++-4.0.1)#ifdef PHP_STANDALONE_EN #include <map> #include <list> #include <stdarg.h>#else #include "WebServer.h"#endif#include "php_syntree.h"#include "php_core_lib.h"PHP_SYN_NODE *g_syn_tree_top = 0;/* scope table */PHP_SCOPE_TABLE g_global_scope = 0;PHP_SCOPE_TABLE g_current_scope = 0;PHP_SCOPE_STACK g_scope_stack = 0;//// Known named constant valuesstd::map<std::string, int> g_known_const;PHP_EXP_NODE *make_zero_exp_node(){ PHP_EXP_NODE *node = new PHP_EXP_NODE; memset(node, 0, sizeof(PHP_EXP_NODE)); return node;}PHP_EXP_NODE *make_const_exp_dnum(int number){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = PHP_OP_VAL; node->val_node.type = PHP_VAL_INT; node->val_node.int_val = number; return node;}PHP_EXP_NODE *make_const_exp_fnum(float number){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = PHP_OP_VAL; node->val_node.type = PHP_VAL_FLOAT; node->val_node.float_val = number; return node;}PHP_EXP_NODE *make_const_exp_str(char *s, int unescape){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = PHP_OP_VAL; node->val_node.type = PHP_VAL_STRING; if ( unescape ) { node->val_node.str_val = (char *)malloc(strlen(s)+1); // copy and unescape string char *p = node->val_node.str_val; while(*s) { if ( *s == '\\' ) { switch ( *(++s) ) { case 'n' : *p++ = '\n'; s++; break; case 't' : *p++ = '\t'; s++; break; default : *p++ = *s++; break; } } else { *p++ = *s++; } } *p = 0; } else { node->val_node.str_val = strdup(s); } return node;}PHP_EXP_NODE *make_const_exp_int_obj(void *obj){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = PHP_OP_VAL; node->val_node.type = PHP_VAL_INT_DATA; node->val_node.ptr_val = obj; return node;}PHP_EXP_NODE *make_exp_1(PHP_EXP_OP op, PHP_EXP_NODE *operand){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = op; node->tree_node.left = operand; return node;}PHP_EXP_NODE *make_exp_2(PHP_EXP_OP op, PHP_EXP_NODE *left, PHP_EXP_NODE *right){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = op; node->tree_node.left = left; node->tree_node.right = right; return node;}PHP_EXP_NODE *make_exp_2_self(PHP_EXP_OP op, PHP_EXP_NODE *self, PHP_EXP_NODE *right){ PHP_EXP_NODE *clone_self = make_zero_exp_node(); *clone_self = *self; return make_exp_2(op, clone_self, right);}PHP_EXP_NODE *make_known_const(char *name){ int const_id = -1; if ( g_known_const.count(name) ) { const_id = g_known_const[name]; } return make_const_exp_dnum(const_id);}//// Create function parameter (in declaration)//PHP_EXP_NODE *make_func_param(PHP_EXP_NODE *list, PHP_EXP_NODE *var_exp_node, char *class_name, int byref){ PHP_FUNC_PARAM_DEF *param = new PHP_FUNC_PARAM_DEF; memset(param, 0, sizeof(PHP_FUNC_PARAM_DEF)); param->si_var = var_exp_node->var_si_node; param->si_var->type = PHP_SCOPE_PARAM; //printf("mark %p->%p as param\n", param->si_var, param->si_var->var); param->var = param->si_var->var; delete var_exp_node; param->class_name = class_name ? strdup(class_name) : 0; param->byref = byref; PHP_EXP_NODE *curr_node = make_const_exp_int_obj(param); if ( list ) { PHP_EXP_NODE *p = list; while ( p->next) { p = p->next; } p->next = curr_node; return list; } else { return curr_node; }}/* * Syntax tree generation */PHP_SYN_NODE *make_expr_syn_node(PHP_STATMENT_TYPE type, PHP_EXP_NODE *expr){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = type; syn_node->node_expr = expr; return syn_node;}PHP_SYN_NODE *make_ifelse_syn_node(PHP_EXP_NODE *expr, PHP_SYN_NODE *then_node, PHP_SYN_NODE *elseif_list, PHP_SYN_NODE *else_node){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = PHP_ST_IF; syn_node->node_if.cond = expr; syn_node->node_if.code_if = then_node; if ( elseif_list ) { syn_node->node_if.code_else = elseif_list; PHP_SYN_NODE *curr_if = elseif_list; while ( curr_if->node_if.code_else ) { curr_if = curr_if->node_if.code_else; } curr_if->node_if.code_else = else_node; } else { syn_node->node_if.code_else = else_node; } return syn_node;}PHP_SYN_NODE *make_while_loop_syn_node(PHP_EXP_NODE *cond, PHP_SYN_NODE *code, int do_while){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = do_while ? PHP_ST_WHILE : PHP_ST_DO_WHILE; syn_node->node_while.cond = cond; syn_node->node_while.code = code; return syn_node;}PHP_SYN_NODE *make_for_syn_node(PHP_EXP_NODE *start, PHP_EXP_NODE *cond, PHP_EXP_NODE *next, PHP_SYN_NODE *code){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = PHP_ST_FOR; syn_node->node_for.do_start = start; syn_node->node_for.cond = cond; syn_node->node_for.do_next = next; syn_node->node_for.code = code; return syn_node;}PHP_SYN_NODE *make_foreach_loop_syn_node(PHP_EXP_NODE *elems, PHP_EXP_NODE *i_key, PHP_EXP_NODE *i_val, PHP_SYN_NODE *code, int byref){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = PHP_ST_FOREACH; syn_node->node_foreach.elems = elems; syn_node->node_foreach.code = code; syn_node->node_foreach.i_key = i_key ? i_key->var_si_node : 0; syn_node->node_foreach.i_val = i_val->var_si_node; syn_node->node_foreach.byref = byref; if ( i_key ) { delete i_key; } delete i_val; return syn_node;}PHP_SYN_NODE *make_func_decl_syn_node(const char *name, PHP_EXP_NODE *param_list){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = PHP_ST_FUNC_DECL; syn_node->func_decl = new PHP_SYN_FUNC_DECL_NODE; memset(syn_node->func_decl, 0, sizeof(PHP_SYN_FUNC_DECL_NODE)); syn_node->func_decl->name = strdup(name); if ( param_list ) { PHP_EXP_NODE *curr_param = param_list; // count parameters first while ( curr_param ) { syn_node->func_decl->param_count++; curr_param = curr_param->next; } syn_node->func_decl->params = new PHP_FUNC_PARAM_DEF[syn_node->func_decl->param_count]; curr_param = param_list; for(int i = 0; param_list; param_list = param_list->next, i++) { syn_node->func_decl->params[i] = *(PHP_FUNC_PARAM_DEF *)param_list->val_node.ptr_val; // param has been copied to array, so it's no longer needed delete (PHP_FUNC_PARAM_DEF *)param_list->val_node.ptr_val; } // dispose linked list as well while ( curr_param ) { PHP_EXP_NODE *p = curr_param->next; delete curr_param; curr_param = p; } } return syn_node;}PHP_SYN_NODE *make_class_decl_syn_node(){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = PHP_ST_CLASS_DECL; syn_node->class_decl = new PHP_SYN_CLASS_DECL_NODE; memset(syn_node->class_decl, 0, sizeof(PHP_SYN_CLASS_DECL_NODE)); return syn_node;}PHP_SYN_NODE *make_switch_syn_node(PHP_EXP_NODE *cond, PHP_EXP_NODE *case_list){ PHP_SYN_NODE *syn_node = new PHP_SYN_NODE; memset(syn_node, 0, sizeof(PHP_SYN_NODE)); syn_node->type = PHP_ST_SWITCH; // // Bind all statement lists into single one for // simplier execution // PHP_SYN_NODE *stat_list_tail = 0; for(PHP_EXP_NODE *cur_case = case_list; cur_case; cur_case = cur_case->next) { PHP_SYN_NODE *cur_stat_list = cur_case->exp_node->tree_node.syn_right; if ( stat_list_tail ) { while ( stat_list_tail->next_node ) stat_list_tail = stat_list_tail->next_node; stat_list_tail->next_node = cur_stat_list; } else { stat_list_tail = cur_stat_list; } } syn_node->node_switch.cond = cond; syn_node->node_switch.case_list = case_list; return syn_node;}PHP_VAR_NODE *make_var_node(){ PHP_VAR_NODE *node = new PHP_VAR_NODE; memset(node, 0, sizeof(PHP_VAR_NODE)); node->value.type = PHP_VAL_NONE; return node;}PHP_VAR_NODE *make_array_var(){ PHP_VAR_NODE *node = make_var_node(); cast_value_array(&node->value); return node;}/* * Called from lexer when ${IDENT} is recognized */PHP_EXP_NODE *get_var_node(const char *name){ PHP_EXP_NODE *node = make_zero_exp_node(); node->op = PHP_OP_VAR; PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, name); if ( si ) { if ( (si->type == PHP_SCOPE_VAR) || (si->type == PHP_SCOPE_PARAM) ) { node->var_si_node = si; } else { // // Error: symbol already defined as different entity // php_report_error(PHP_ERROR, "symbol [%s] already defined as different entity (%d)", name, si->type); } } else { add_var_2_scope(g_current_scope, make_var_node(), name); node->var_si_node = get_scope_item(g_current_scope, name); } return node;}void free_var_node(PHP_VAR_NODE *v){ delete v;}/* * Init function scope table before transferring control there. * 1. Evaluate all by-value params * 2. Lvalue-evaluate all by-ref params and adjust pointers */void func_scope_init(PHP_FUNC_PARAM_DEF *params, int param_count, PHP_SCOPE_TABLE_TYPE * /*scope_map*/, PHP_VALUE_NODE *arg_array, std::map<std::string, PHP_VAR_NODE *> &saved_vars){ // // Step 1: save origival vars PHP_SCOPE_TABLE_TYPE *curr_scope_map = (PHP_SCOPE_TABLE_TYPE *)g_current_scope; for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();i++) { if ( (i->second->type == PHP_SCOPE_VAR) || (i->second->type == PHP_SCOPE_PARAM) ) { if ( !(i->second->var->flags & PHP_VARFLAG_STATIC) ) { //printf("Saving %s = %p->%p\n", i->first.c_str(), i->second, i->second->var); saved_vars[i->first] = i->second->var; } } } // // Step 2: calculate new values of call parameters PHP_VAR_NODE *call_params[PHP_MAX_FUNC_PARAM]; for(int i = 0; i < param_count; i++) { PHP_VAR_NODE *curr_arg_val = array_get_by_int_key(arg_array, i); if ( curr_arg_val->value.type != PHP_VAL_NONE ) { if ( (curr_arg_val->flags & PHP_VARFLAG_BYREF) || params[i].byref ) { call_params[i] = php_expr_eval_lvalue((PHP_EXP_NODE *)curr_arg_val->value.ptr_val); if ( !call_params[i] ) { php_report_error(PHP_ERROR, "Byref parameter is not lvalue"); return; } } else { call_params[i] = make_var_node(); call_params[i]->ref_count = 1; //printf("alloc var for callparam %d -> %p\n", i, call_params[i]); php_expr_eval((PHP_EXP_NODE *)curr_arg_val->value.ptr_val, &call_params[i]->value); } } else { // put default value php_report_error(PHP_WARNING, "Default parameters are not implemented yet"); call_params[i] = make_var_node(); call_params[i]->ref_count = 1; } } // // Step 3: assign new values to call parameters for(int i = 0; i < param_count; i++) { //printf("assign new param si=%p var=%p -> %p\n", params[i].si_var, params[i].si_var->var, call_params[i]); params[i].si_var->var = call_params[i]; } // // Step 4: allocate new stack local vars for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();i++) { if ( !((i->second->type == PHP_SCOPE_PARAM) || (i->second->type == PHP_SCOPE_VAR)) ) { continue; } //printf("in scope: %p %s [ %s ] with flags %02x\n", i->second, i->second->type == PHP_SCOPE_PARAM ? "param" : "var", // i->first.c_str(), i->second->var->flags); if ( !(i->second->var->flags & PHP_VARFLAG_STATIC) && (i->second->type != PHP_SCOPE_PARAM) ) { //printf("alloc new for %s [ %p->%p ]\n", i->first.c_str(), i->second, i->second->var); i->second->var = make_var_node(); i->second->var->ref_count = 1; } }}/* * Since by-ref params changes pointers in scope table, we need to restore them * to original objects, so: * 1. Memory will not leak * 2. Next call may be using same params by-value, so it need independent varnode */void func_scope_copy_back(PHP_FUNC_PARAM_DEF *params, int param_count, PHP_SCOPE_TABLE_TYPE * /*scope_map*/, PHP_VALUE_NODE *arg_array, std::map<std::string, PHP_VAR_NODE *> &saved_vars){ /* if ( param_count < array_get_size(arg_array) ) { param_count = array_get_size(arg_array); } */ PHP_VAR_NODE *call_params[PHP_MAX_FUNC_PARAM]; int call_param_2free_count = 0; for(int i = 0; i < param_count; i++) { PHP_VAR_NODE *curr_arg_val = array_get_by_int_key(arg_array, i); if ( !((curr_arg_val->flags & PHP_VARFLAG_BYREF) || params[i].byref) ) { //printf("Delete param %d %p->%p\n", i, params[i].si_var, params[i].si_var->var); call_params[call_param_2free_count++] = params[i].si_var->var; } params[i].si_var->var = params[i].var; } PHP_SCOPE_TABLE_TYPE *curr_scope_map = (PHP_SCOPE_TABLE_TYPE *)g_current_scope; for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();i++) { if ( (i->second->type == PHP_SCOPE_VAR) || (i->second->type == PHP_SCOPE_PARAM) ) { if ( !(i->second->var->flags & PHP_VARFLAG_STATIC) ) { //printf("Restoring %s = %p->%p\n", i->first.c_str(), i->second, i->second->var); //assert(saved_vars[i->first]); if (i->second->type == PHP_SCOPE_VAR) { value_value_free(&i->second->var->value); delete i->second->var; } i->second->var = saved_vars[i->first]; } } } for(int i = 0; i < call_param_2free_count; i++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -