📄 php_syntree.cpp
字号:
PHP_SCOPE_TABLE func_scope = make_scope_table(); PHP_SYN_NODE *decl_node = make_func_decl_syn_node(def->name, 0); decl_node->func_decl->param_count = def->param_count; decl_node->func_decl->params = new PHP_FUNC_PARAM_DEF[def->param_count]; // // Built-in functions don't have class specifier, and can handle // default arguments internally // memset(decl_node->func_decl->params, 0, sizeof(PHP_FUNC_PARAM_DEF) * def->param_count); for(int i = 0; i < def->param_count;i++) { PHP_VAR_NODE *func_param = make_var_node(); char param_name[32]; snprintf(param_name, sizeof(param_name), "__param_%d", i); decl_node->func_decl->params[i].def_value.type = PHP_VAL_NONE; decl_node->func_decl->params[i].var = func_param; decl_node->func_decl->params[i].si_var = add_var_2_scope(func_scope, func_param, param_name); decl_node->func_decl->params[i].si_var->type = PHP_SCOPE_PARAM; } decl_node->func_decl->scope = func_scope; decl_node->func_decl->is_native = 1; decl_node->func_decl->native_ptr = def->func; add_func_2_scope(g_global_scope, decl_node);}void php_add_native_class(const char *name, PHP_NATIVE_PROP_GET_FUNC_PTR prop_get_native_ptr){ if ( get_scope_item_type(g_global_scope, name) != PHP_SCOPE_NONE ) { // // Error: something already defined by this name // php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined"); return; } PHP_SYN_NODE *decl_node = make_class_decl_syn_node(); decl_node->class_decl->name = strdup(name); decl_node->class_decl->is_native = 1; decl_node->class_decl->native_prop_get_ptr = prop_get_native_ptr; add_class_2_scope(g_global_scope, decl_node);}void php_engine_init(){ g_global_scope = make_scope_table(); g_current_scope = g_global_scope; g_scope_stack = new PHP_SCOPE_STACK_TYPE; // here built-in functions/objects/vars are loaded php_init_core_lib(); php_init_amule_lib();}void php_exp_tree_free(PHP_EXP_NODE *tree){ if ( !tree ) { return; } switch ( tree->op ) { case PHP_OP_VAR: /* will be deleted during scope table destruction */ break; case PHP_OP_VAL: value_value_free(&tree->val_node); break; case PHP_OP_FUNC_CALL: { php_exp_tree_free(tree->tree_node.left); PHP_VAR_NODE *args = tree->tree_node.right->var_node; PHP_VALUE_NODE *args_array = &args->value; for(PHP_ARRAY_ITER_TYPE i = ((PHP_ARRAY_TYPE *)args_array->ptr_val)->array.begin(); i != ((PHP_ARRAY_TYPE *)args_array->ptr_val)->array.end(); i++) { PHP_VAR_NODE *var_i = i->second; php_exp_tree_free((PHP_EXP_NODE *)var_i->value.ptr_val); } value_value_free(&args->value); delete tree->tree_node.right->var_node; delete tree->tree_node.right; } break; case PHP_OP_ARRAY: { PHP_EXP_NODE *curr = tree->tree_node.left; while (curr) { PHP_EXP_NODE *next = curr->next; php_exp_tree_free(curr->exp_node); delete curr; curr = next; } } break; case PHP_OP_MUX: php_exp_tree_free(tree->exp_node); default: // all other things using left/right php_exp_tree_free(tree->tree_node.left); php_exp_tree_free(tree->tree_node.right); } delete tree;}void php_syn_tree_free(PHP_SYN_NODE *tree){ while ( tree ) { switch ( tree->type ) { case PHP_ST_EXPR: case PHP_ST_RET: php_exp_tree_free(tree->node_expr); break; case PHP_ST_ECHO: { PHP_EXP_NODE *curr = tree->node_expr; while (curr) { PHP_EXP_NODE *next = curr->next; php_exp_tree_free(curr->exp_node); delete curr; curr = next; } } break; case PHP_ST_IF: php_exp_tree_free(tree->node_if.cond); php_syn_tree_free(tree->node_if.code_if); php_syn_tree_free(tree->node_if.code_else); break; case PHP_ST_WHILE: case PHP_ST_DO_WHILE: php_exp_tree_free(tree->node_while.cond); php_syn_tree_free(tree->node_while.code); break; case PHP_ST_FOR: php_exp_tree_free(tree->node_for.do_start); php_exp_tree_free(tree->node_for.cond); php_exp_tree_free(tree->node_for.do_next); php_syn_tree_free(tree->node_for.code); break; case PHP_ST_FOREACH: php_exp_tree_free(tree->node_foreach.elems); php_syn_tree_free(tree->node_foreach.code); break; case PHP_ST_CONTINUE: case PHP_ST_BREAK: break; case PHP_ST_FUNC_DECL: if ( !tree->func_decl->is_native ) { php_syn_tree_free(tree->func_decl->code); } delete_scope_table(tree->func_decl->scope); free(tree->func_decl->name); for(int i = 0; i < tree->func_decl->param_count; i++) { if (tree->func_decl->params[i].class_name) { free(tree->func_decl->params[i].class_name); } } delete [] tree->func_decl->params; delete tree->func_decl; break; case PHP_ST_SWITCH: { php_exp_tree_free(tree->node_switch.cond); php_syn_tree_free(tree->node_switch.case_list->exp_node->tree_node.syn_right); PHP_EXP_NODE *curr = tree->node_switch.case_list; while (curr) { PHP_EXP_NODE *next = curr->next; if ( curr->exp_node ) { php_exp_tree_free(curr->exp_node->tree_node.left); delete curr->exp_node; } delete curr; curr = next; } } break; case PHP_ST_CLASS_DECL: free(tree->class_decl->name); delete tree->class_decl; break; } PHP_SYN_NODE *next_node = tree->next_node; delete tree; tree = next_node; }} void php_engine_free(){ if ( g_global_scope ) { delete_scope_table(g_global_scope); } php_syn_tree_free(g_syn_tree_top); g_global_scope = 0; g_current_scope = 0; delete (PHP_SCOPE_STACK_TYPE *)g_scope_stack;}/* * Create reference. This is recoursive process, since operators [] * can be stacked: $a[1][2][3] = & $b; * There's 3 valid cases in making reference: * 1,2. Target is scalar variable or variable by name ${xxx} * 3. Target is member of array. */void exp_set_ref(PHP_EXP_NODE *expr, PHP_VAR_NODE *var, PHP_VALUE_NODE *key){ switch ( expr->op ) { case PHP_OP_VAR: { if ( expr->var_si_node->var != var ) { if ( key ) { cast_value_array(&expr->var_si_node->var->value); array_set_by_key(&expr->var_si_node->var->value, key, var); } else { var_node_free(expr->var_si_node->var); expr->var_si_node->var = var; var->ref_count++; } } } break; case PHP_OP_ARRAY_BY_KEY: { PHP_VALUE_NODE i_key; i_key.type = PHP_VAL_NONE; php_expr_eval(expr->tree_node.right, &i_key); exp_set_ref(expr->tree_node.left, var, &i_key); } break; default: php_report_error(PHP_ERROR, "Bad left part of operator =&: (%d)", expr->tree_node.left->op); }}/* * This is heart of expression tree: evaluation. It's split into 2 functions * where 1 evaluates "value" of expression, and other evaluates "lvalue" i.e. assignable * entity from given subtree. */void php_expr_eval(PHP_EXP_NODE *expr, PHP_VALUE_NODE *result){ PHP_VALUE_NODE result_val_right, result_val_left; PHP_VAR_NODE *lval_node = 0; PHP_SCOPE_ITEM *si = 0; result_val_right.type = PHP_VAL_NONE; result_val_left.type = PHP_VAL_NONE; switch(expr->op) { case PHP_OP_VAL: if ( result ) { value_value_assign(result, &expr->val_node); } break; case PHP_OP_VAR: if ( result ) { value_value_assign(result, &expr->var_si_node->var->value); } break; case PHP_OP_ASS: lval_node = php_expr_eval_lvalue(expr->tree_node.left); if ( !lval_node ) { break; } php_expr_eval(expr->tree_node.right, &lval_node->value); if ( result ) { value_value_assign(result, &lval_node->value); } break; case PHP_OP_ARRAY_BY_KEY: php_expr_eval(expr->tree_node.right, &result_val_right); lval_node = php_expr_eval_lvalue(expr->tree_node.left); cast_value_array(&lval_node->value); cast_value_str(&result_val_right); lval_node = array_get_by_key(&lval_node->value, &result_val_right); if ( result ) { value_value_assign(result, &lval_node->value); } break; case PHP_MAKE_REF: lval_node = php_expr_eval_lvalue(expr->tree_node.right); if ( !lval_node ) { break; } exp_set_ref(expr->tree_node.left, lval_node, 0); break; case PHP_OP_ARRAY: if ( result ) { PHP_EXP_NODE *curr = expr->tree_node.left; value_value_free(result); cast_value_array(result); while ( curr ) { switch( curr->exp_node->op ) { case PHP_OP_ARRAY_PAIR: if ( curr->exp_node->tree_node.right ) { php_expr_eval(curr->exp_node->tree_node.left, &result_val_left); cast_value_str(&result_val_left); lval_node = array_get_by_key(result, &result_val_left); value_value_free(&result_val_left); php_expr_eval(curr->exp_node->tree_node.right, &lval_node->value); } else { lval_node = array_push_back(result); php_expr_eval(curr->exp_node->tree_node.left, &lval_node->value); } break; case PHP_OP_ARRAY_REF_PAIR: lval_node = php_expr_eval_lvalue(curr->exp_node->tree_node.right); break; default: php_report_error(PHP_INTERNAL_ERROR, "Array list contain wrong node"); return; } curr = curr->next; } } break; case PHP_OP_FUNC_CALL: php_run_func_call(expr, result); break; case PHP_OP_LIST: { PHP_EXP_NODE *curr = expr; while ( curr ) { if ( curr->exp_node ) { php_expr_eval(curr->exp_node, result); } curr = curr->next; } } break; case PHP_OP_CAT: php_expr_eval(expr->tree_node.right, &result_val_right); php_expr_eval(expr->tree_node.left, &result_val_left); if ( result ) { cast_value_str(&result_val_left); cast_value_str(&result_val_right); value_value_free(result); result->type = PHP_VAL_STRING; // using "malloc" and not "new" since all strings are freed // later with "free" and not "delete" result->str_val = (char *)malloc(strlen(result_val_left.str_val) + strlen(result_val_right.str_val) + 1); strcpy(result->str_val, result_val_left.str_val); strcat(result->str_val, result_val_right.str_val); } break; case PHP_OP_MUX: php_expr_eval(expr->exp_node, &result_val_right); cast_value_bool(&result_val_right); if ( result_val_right.int_val ) { php_expr_eval(expr->tree_node.left, result); } else { php_expr_eval(expr->tree_node.right, result); } break; case PHP_OP_CAST_INT: if ( result ) { php_expr_eval(expr->tree_node.left, result); cast_value_dnum(result); } break; case PHP_OP_CAST_FLOAT: if ( result ) { php_expr_eval(expr->tree_node.left, result); cast_value_fnum(result); } break; case PHP_OP_CAST_BOOL: if ( result ) { php_expr_eval(expr->tree_node.left, result); cast_value_bool(result); } break; case PHP_OP_CAST_STR: if ( result ) { php_expr_eval(expr->tree_node.left, result); cast_value_str(result); } break; case PHP_OP_LOG_NOT: if ( result ) { php_expr_eval(expr->tree_node.left, &result_val_right); cast_value_bool(&result_val_right); result_val_right.int_val = !result_val_right.int_val; value_value_assign(result, &result_val_right); } break; case PHP_OP_NOT: if ( result ) { php_expr_eval(expr->tree_node.left, &result_val_right); cast_value_bool(&result_val_right); result_val_right.int_val = ~result_val_right.int_val; value_value_assign(result, &result_val_right); } break; case PHP_OP_ADD: case PHP_OP_SUB: case PHP_OP_MUL: case PHP_OP_DIV: php_expr_eval(expr->tree_node.right, &result_val_right); php_expr_eval(expr->tree_node.left, &result_val_left); if ( result ) { php_eval_simple_math(expr->op, &result_val_left, &result_val_right, result); } break; case PHP_OP_SHL: case PHP_OP_SHR: case PHP_OP_OR: case PHP_OP_AND: case PHP_OP_XOR: case PHP_OP_LOG_OR: case PHP_OP_LOG_AND: case PHP_OP_LOG_XOR: php_expr_eval(expr->tree_node.right, &result_val_right); php_expr_eval(expr->tree_node.left, &result_val_left); if ( result ) { php_eval_int_math(expr->op, &result_val_left, &result_val_right, result); } break; case PHP_OP_EQ: case PHP_OP_NEQ: case PHP_OP_GRT: case PHP_OP_LWR: php_expr_eval(expr->tree_node.right, &result_val_right); php_expr_eval(expr->tree_node.left, &result_val_left); if ( result ) { php_eval_compare(expr->op, &result_val_left, &result_val_right, result); } break; case PHP_OP_PRINT: php_expr_eval(expr->tree_node.left, &result_val_right); cast_value_str(&result_val_right); // // I print to buffer CPhPLibContext::Print(result_val_right.str_val); break; case PHP_OP_OBJECT_DEREF: // $x->y // take variable from scope of current object lval_node = php_expr_eval_lvalue(expr->tree_node.left); if ( !lval_node ) { php_report_error(PHP_ERROR, "Left part of -> must be lvalue"); return; } if ( lval_node->value.type != PHP_VAL_OBJECT ) { php_report_error(PHP_ERROR, "Left part of -> must be an object"); return; } if ( get_scope_item_type(g_global_scope, lval_node->value.obj_val.class_name) == PHP_SCOPE_NONE ) { php_report_error(PHP_ERROR, "Undeclared object"); return; } si = get_scope_item(g_global_scope, lval_node->value.obj_val.class_name); if ( si->type != PHP_SCOPE_CLASS ) { php_report_error(PHP_INTERNAL_ERROR, "Object classname is not name of class"); return; } // left part is ok, let's check the right if ( (expr->tree_node.right->op != PHP_OP_VAL) || (expr->tree_node.right->val_node.type != PHP_VAL_STRING) ) { php_report_error(PHP_ERROR, "Right part of -> must be string value"); return; } if ( si->class_decl->class_decl->is_native ) { si->class_decl->class_decl->native_prop_get_ptr(lval_node->value.obj_val.inst_ptr, expr->tree_node.right->val_node.str_val, result); } else { php_report_error(PHP_ERROR, "Only native classes supported"); return; } break; case PHP_OP_CLASS_DEREF: // A::y // take variable (static) from scope of current class php_report_error(PHP_ERROR, "Value of static class members not supported"); break; default: ; } value_value_free(&result_val_left); value_value_free(&result_val_right);}PHP_VAR_NODE *php_expr_eval_lvalue(PHP_EXP_NODE *expr){ PHP_VAR_NODE *lval_node = 0; PHP_VALUE_NODE index; index.type = PHP_VAL_NONE; switch(expr->op) { case PHP_OP_VAR: lval_node = expr->var_si_node->var; break; case PHP_OP_ARRAY_BY_KEY: lval_node = php_expr_eval_lvalue(expr->tree_node.left); if ( !lval_node ) { break; } cast_value_array(&lval_node->value); if ( expr->tree_node.right ) { php_expr_eval(expr->tree_node.right, &index); if ( index.type == PHP_VAL_NONE ) { // something got wrong: evaluation result is not a value return 0; } cast_value_str(&index); lval_node = array_get_by_key(&lval_node->value, &index); value_value_free(&index); } else { // this is "$xxx[] = " construct.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -