📄 php_syntree.cpp
字号:
lval_node = array_push_back(&lval_node->value); } case PHP_OP_VAR_BY_EXP: // ${"xxx"} // should take variable from current scope break; case PHP_OP_OBJECT_DEREF: // $x->y // take variable from scope of current object php_report_error(PHP_ERROR, "Assign to class members not supported"); break; case PHP_OP_CLASS_DEREF: // A::y // take variable (static) from scope of current class php_report_error(PHP_ERROR, "Assign to static class members not supported"); break; default: // // Error: expression can not be taken as lvalue // php_report_error(PHP_ERROR, "This expression can't be used as lvalue"); } return lval_node;}PHP_VALUE_TYPE cast_type_resolve(PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2){ if ( (op1->type == PHP_VAL_FLOAT) || (op2->type == PHP_VAL_FLOAT) ) { cast_value_fnum(op1); cast_value_fnum(op2); return PHP_VAL_FLOAT; } else { cast_value_dnum(op1); cast_value_dnum(op2); return PHP_VAL_INT; }}/* * Same as simple_math, but result is always bool */void php_eval_compare(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result){ result->type = PHP_VAL_BOOL; if ( (op1->type == PHP_VAL_STRING) || (op2->type == PHP_VAL_STRING) ) { cast_value_str(op1); cast_value_str(op2); int cmp_val = strcmp(op1->str_val, op2->str_val); switch(op) { case PHP_OP_EQ: result->int_val = (cmp_val == 0); break; case PHP_OP_NEQ: result->int_val = (cmp_val != 0); break; case PHP_OP_GRT: result->int_val = (cmp_val > 0); break; case PHP_OP_LWR: result->int_val = (cmp_val < 0); break; case PHP_OP_GRT_EQ: result->int_val = (cmp_val >= 0); break; case PHP_OP_LWR_EQ: result->int_val = (cmp_val <= 0); break; default: php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op"); } } else { PHP_VALUE_TYPE restype = cast_type_resolve(op1, op2); switch(op) { case PHP_OP_EQ: if ( restype == PHP_VAL_FLOAT ) { result->int_val = op1->float_val == op2->float_val; } else { result->int_val = op1->int_val == op2->int_val; } break; case PHP_OP_NEQ: if ( restype == PHP_VAL_FLOAT ) { result->int_val = op1->float_val != op2->float_val; } else { result->int_val = op1->int_val != op2->int_val; } break; case PHP_OP_GRT: if ( restype == PHP_VAL_FLOAT ) { result->int_val = op1->float_val > op2->float_val; } else { result->int_val = op1->int_val > op2->int_val; } break; case PHP_OP_GRT_EQ: if ( restype == PHP_VAL_FLOAT ) { result->int_val = op1->float_val >= op2->float_val; } else { result->int_val = op1->int_val >= op2->int_val; } break; case PHP_OP_LWR: if ( restype == PHP_VAL_FLOAT ) { result->int_val = op1->float_val < op2->float_val; } else { result->int_val = op1->int_val < op2->int_val; } break; case PHP_OP_LWR_EQ: if ( restype == PHP_VAL_FLOAT ) { result->int_val = op1->float_val <= op2->float_val; } else { result->int_val = op1->int_val <= op2->int_val; } break; default: php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op"); } }}void php_eval_simple_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result){ result->type = cast_type_resolve(op1, op2); switch(op) { case PHP_OP_ADD: if ( result->type == PHP_VAL_FLOAT ) { result->float_val = op1->float_val + op2->float_val; } else { result->int_val = op1->int_val + op2->int_val; } break; case PHP_OP_SUB: if ( result->type == PHP_VAL_FLOAT ) { result->float_val = op1->float_val - op2->float_val; } else { result->int_val = op1->int_val - op2->int_val; } break; case PHP_OP_MUL: if ( result->type == PHP_VAL_FLOAT ) { result->float_val = op1->float_val * op2->float_val; } else { result->int_val = op1->int_val * op2->int_val; } break; case PHP_OP_DIV: if ( result->type == PHP_VAL_FLOAT ) { result->float_val = op1->float_val / op2->float_val; } else { result->int_val = op1->int_val / op2->int_val; } break; default: php_report_error(PHP_INTERNAL_ERROR, "This op is not simple math"); }}void php_eval_int_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result){ cast_value_dnum(op1); cast_value_dnum(op2); result->type = PHP_VAL_INT; switch(op) { case PHP_OP_SHL: result->int_val = op1->int_val << op2->int_val; break; case PHP_OP_SHR: result->int_val = op1->int_val >> op2->int_val; break; case PHP_OP_OR: result->int_val = op1->int_val | op2->int_val; break; case PHP_OP_LOG_OR: result->int_val = op1->int_val || op2->int_val; break; case PHP_OP_AND: result->int_val = op1->int_val & op2->int_val; break; case PHP_OP_LOG_AND: result->int_val = op1->int_val && op2->int_val; break; case PHP_OP_LOG_XOR: op1->int_val = op1->int_val ? 1 : 0; op2->int_val = op2->int_val ? 1 : 0; case PHP_OP_XOR: result->int_val = op1->int_val ^ op2->int_val; break; default: php_report_error(PHP_INTERNAL_ERROR, "This op is not int math"); }}//// left = VAR(func_name), right=ARRAY(args)void php_run_func_call(PHP_EXP_NODE *node, PHP_VALUE_NODE *result){ PHP_EXP_NODE *l_node = node->tree_node.left; PHP_EXP_NODE *r_node = node->tree_node.right; if ( (l_node->op != PHP_OP_VAL) || (l_node->val_node.type != PHP_VAL_STRING) || (r_node->op != PHP_OP_VAR) || (r_node->var_node->value.type != PHP_VAL_ARRAY) ) { // // Internal error: function name must be string value node, and // params must be an array // php_report_error(PHP_INTERNAL_ERROR, "Function call node have wrong data"); return ; } PHP_SCOPE_ITEM *si = get_scope_item(g_global_scope, l_node->val_node.str_val); if ( !si ) { // // Error: undeclared symbol // php_report_error(PHP_ERROR, "Function [ %s ] is not defined", l_node->val_node.str_val); return; } if ( si->type != PHP_SCOPE_FUNC) { // // Error: defined, but wrong type ! // php_report_error(PHP_ERROR, "Item [ %s ] is not a function", l_node->val_node.str_val); return; } PHP_SYN_NODE *func = si->func; if ( func->type != PHP_ST_FUNC_DECL ) { // // Internal error: node not a function // php_report_error(PHP_INTERNAL_ERROR, "Wrong type in function decl node"); return; } // // Switch stack and call function // PHP_SYN_FUNC_DECL_NODE *func_decl = func->func_decl; std::map<std::string, PHP_VAR_NODE *> saved_vars; func_scope_init(func_decl->params, func_decl->param_count, (PHP_SCOPE_TABLE_TYPE *)func_decl->scope, &r_node->var_node->value, saved_vars); switch_push_scope_table((PHP_SCOPE_TABLE_TYPE *)func_decl->scope); if ( func_decl->is_native ) { func_decl->native_ptr(result); } else { php_execute(func_decl->code, result); } // // restore stack, free arg list // switch_pop_scope_table(0); func_scope_copy_back(func_decl->params, func_decl->param_count, (PHP_SCOPE_TABLE_TYPE *)func_decl->scope, &r_node->var_node->value, saved_vars); //scope_reset_nonstatics(func_decl->scope); }/* * Theoretically speaking this function must run on generated code. On the * practical side - I need it to debug syntax tree generation. Later, it can * be changes to generate code for some kind of bytecode for stack machine */int php_execute(PHP_SYN_NODE *node, PHP_VALUE_NODE *result){ if ( !node ) { return 0; } int curr_exec_result; while ( node ) { curr_exec_result = 0; PHP_VALUE_NODE cond_result; cond_result.type = PHP_VAL_NONE; switch (node->type) { case PHP_ST_EXPR: php_expr_eval(node->node_expr, 0); break; case PHP_ST_IF: php_expr_eval(node->node_if.cond, &cond_result); cast_value_bool(&cond_result); if ( cond_result.int_val ) { if ( node->node_if.code_if ) { curr_exec_result = php_execute(node->node_if.code_if, result); } } else { if ( node->node_if.code_else ) { curr_exec_result = php_execute(node->node_if.code_else, result); } } break; case PHP_ST_RET: if ( node->node_expr ) { php_expr_eval(node->node_expr, result); } if ( node->next_node ) { // // Warning: code after "return" statement // php_report_error(PHP_WARNING, "code after 'return'"); } // "return" is ultimate "break" curr_exec_result = -0xffff; break; case PHP_ST_ECHO: { PHP_EXP_NODE *curr = node->node_expr; while (curr) { php_expr_eval(curr->exp_node, &cond_result); cast_value_str(&cond_result); CPhPLibContext::Print(cond_result.str_val); value_value_free(&cond_result); curr = curr->next; } } break; case PHP_ST_CONTINUE: case PHP_ST_BREAK: if ( node->node_expr ) { php_expr_eval(node->node_expr, &cond_result); } else { cond_result.type = PHP_VAL_INT; cond_result.int_val = 1; } cast_value_dnum(&cond_result); if ( node->type == PHP_ST_BREAK ) { curr_exec_result = -cond_result.int_val; } else { curr_exec_result = cond_result.int_val; } break; case PHP_ST_WHILE: case PHP_ST_DO_WHILE: if ( node->type == PHP_ST_WHILE ) { php_expr_eval(node->node_while.cond, &cond_result); cast_value_bool(&cond_result); } else { cond_result.int_val = 1; } while ( cond_result.int_val ) { curr_exec_result = php_execute(node->node_while.code, 0); if ( curr_exec_result < 0 ) { break; } php_expr_eval(node->node_while.cond, &cond_result); cast_value_bool(&cond_result); } break; case PHP_ST_FOR: php_expr_eval(node->node_for.do_start, &cond_result); php_expr_eval(node->node_for.cond, &cond_result); cast_value_bool(&cond_result); while ( cond_result.int_val ) { curr_exec_result = php_execute(node->node_for.code, 0); if ( curr_exec_result < 0 ) { break; } php_expr_eval(node->node_for.do_next, &cond_result); php_expr_eval(node->node_for.cond, &cond_result); cast_value_bool(&cond_result); } break; case PHP_ST_FOREACH: { PHP_VAR_NODE *elems = php_expr_eval_lvalue(node->node_foreach.elems); if ( !elems || (elems->value.type != PHP_VAL_ARRAY) ) { php_report_error(PHP_ERROR, "Argument of 'foreach' must be array"); break; } PHP_ARRAY_TYPE *array = (PHP_ARRAY_TYPE *)elems->value.ptr_val; PHP_SCOPE_ITEM *i_key = node->node_foreach.i_key; // keys in array are string values. if ( i_key ) { i_key->var->value.type = PHP_VAL_STRING; } PHP_SCOPE_ITEM *i_val = node->node_foreach.i_val; array->current = array->sorted_keys.begin(); while ( array->current != array->sorted_keys.end() ) { if ( i_key ) { PHP_VALUE_NODE tmp_val; tmp_val.type = PHP_VAL_STRING; tmp_val.str_val = (char *)array->current->c_str(); value_value_assign(&i_key->var->value, &tmp_val); } PHP_VALUE_NODE *curr_value = &array->array[*array->current]->value; value_value_assign(&i_val->var->value, curr_value); curr_exec_result = php_execute(node->node_foreach.code, 0); if ( i_key ) { value_value_free(&i_key->var->value); } if ( node->node_foreach.byref ) { value_value_assign(curr_value, &i_val->var->value); } value_value_free(&i_val->var->value); if ( curr_exec_result < 0 ) { break; } array->current++; } } break; case PHP_ST_SWITCH: { PHP_SYN_NODE *cur_exec = 0; php_expr_eval(node->node_switch.cond, &cond_result); PHP_EXP_NODE *curr = node->node_switch.case_list; while (curr) { PHP_VALUE_NODE cur_value, cmp_result; cur_value.type = cmp_result.type = PHP_VAL_NONE; php_expr_eval(curr->exp_node->tree_node.left, &cur_value); php_eval_compare(PHP_OP_EQ, &cur_value, &cond_result, &cmp_result); if ( cmp_result.int_val ) { cur_exec = (PHP_SYN_NODE *)curr->exp_node->tree_node.syn_right; break; } curr = curr->next; } if ( cur_exec ) { php_execute(cur_exec, result); } } break; default: ; } if ( curr_exec_result ) { return curr_exec_result; } node = node->next_node; } // everything ok, keep going return 0;}//// call it when something gone wrong//void php_report_error(PHP_MSG_TYPE err_type, const char *msg, ...){ // // hope my error message will never be that big. // // security is ok, since _user_ errors are not reporting thru // this function, but handled by scipt itself. // However, badly written script MAY force user-supplied data to // leak here and create stack overrun exploit. Be warned. // char msgbuf[1024]; const char *type_msg = 0; switch(err_type) { case PHP_MESAGE: type_msg = "PHP:"; break; case PHP_WARNING: type_msg = "PHP Warning:"; break; case PHP_ERROR: type_msg = "PHP Error:"; break; case PHP_INTERNAL_ERROR: type_msg = "PHP Internal Error:"; break; } va_list args; va_start(args, msg); vsnprintf(msgbuf, sizeof(msgbuf), msg, args); va_end(args); printf("%s %s\n", type_msg, msgbuf); assert(err_type != PHP_INTERNAL_ERROR);}int yyerror(char *s){ printf("ERROR in grammar %s after [%s] near line %d\n", s, yytext, yylineno); return 0;}#ifdef PHP_STANDALONE_ENint main(int argc, char *argv[]){ const char *filename = ( argc == 2 ) ? argv[1] : "test.php"; CWriteStrBuffer buffer; yydebug = 0; CPhpFilter php_filter((CWebServerBase*)0, (CSession *)0,filename, &buffer); int size = buffer.Length(); char *buf = new char [size+1]; buffer.CopyAll(buf); printf("%s", buf); delete [] buf; return 0;}#endif// File_checked_for_headers
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -