C++11 requires a space between literal and string macro
[amule.git] / src / webserver / src / php_syntree.cpp
blobe287ba48dffd114fb3344d329e8ff57b6b2b54c7
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2005-2011 Froenchenko Leonid ( lfroen@gmail.com / http://www.amule.org )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include <string> // Do_not_auto_remove (g++-4.0.1)
29 #ifdef PHP_STANDALONE_EN
30 #include <map>
31 #include <list>
32 #include <stdarg.h>
33 #else
34 #include "WebServer.h"
35 #endif
38 #include "php_syntree.h"
39 #include "php_core_lib.h"
42 PHP_SYN_NODE *g_syn_tree_top = 0;
44 /* scope table */
45 PHP_SCOPE_TABLE g_global_scope = 0;
46 PHP_SCOPE_TABLE g_current_scope = 0;
47 PHP_SCOPE_STACK g_scope_stack = 0;
51 // Known named constant values
52 std::map<std::string, int> g_known_const;
54 PHP_EXP_NODE *make_zero_exp_node()
56 PHP_EXP_NODE *node = new PHP_EXP_NODE;
57 memset(node, 0, sizeof(PHP_EXP_NODE));
58 return node;
61 PHP_EXP_NODE *make_const_exp_dnum(int number)
63 PHP_EXP_NODE *node = make_zero_exp_node();
64 node->op = PHP_OP_VAL;
65 node->val_node.type = PHP_VAL_INT;
66 node->val_node.int_val = number;
68 return node;
71 PHP_EXP_NODE *make_const_exp_fnum(float number)
73 PHP_EXP_NODE *node = make_zero_exp_node();
74 node->op = PHP_OP_VAL;
75 node->val_node.type = PHP_VAL_FLOAT;
76 node->val_node.float_val = number;
78 return node;
81 PHP_EXP_NODE *make_const_exp_str(char *s, int unescape)
83 PHP_EXP_NODE *node = make_zero_exp_node();
84 node->op = PHP_OP_VAL;
85 node->val_node.type = PHP_VAL_STRING;
87 if ( unescape ) {
88 node->val_node.str_val = (char *)malloc(strlen(s)+1);
89 // copy and unescape string
90 char *p = node->val_node.str_val;
91 while(*s) {
92 if ( *s == '\\' ) {
93 switch ( *(++s) ) {
94 case 'n' : *p++ = '\n'; s++; break;
95 case 't' : *p++ = '\t'; s++; break;
96 default : *p++ = *s++; break;
98 } else {
99 *p++ = *s++;
102 *p = 0;
103 } else {
104 node->val_node.str_val = strdup(s);
107 return node;
110 PHP_EXP_NODE *make_const_exp_int_obj(void *obj)
112 PHP_EXP_NODE *node = make_zero_exp_node();
113 node->op = PHP_OP_VAL;
114 node->val_node.type = PHP_VAL_INT_DATA;
115 node->val_node.ptr_val = obj;
117 return node;
120 PHP_EXP_NODE *make_exp_1(PHP_EXP_OP op, PHP_EXP_NODE *operand)
122 PHP_EXP_NODE *node = make_zero_exp_node();
123 node->op = op;
124 node->tree_node.left = operand;
125 return node;
128 PHP_EXP_NODE *make_exp_2(PHP_EXP_OP op, PHP_EXP_NODE *left, PHP_EXP_NODE *right)
130 PHP_EXP_NODE *node = make_zero_exp_node();
131 node->op = op;
132 node->tree_node.left = left;
133 node->tree_node.right = right;
134 return node;
137 PHP_EXP_NODE *make_exp_2_self(PHP_EXP_OP op, PHP_EXP_NODE *self, PHP_EXP_NODE *right)
139 PHP_EXP_NODE *clone_self = make_zero_exp_node();
140 *clone_self = *self;
141 return make_exp_2(op, clone_self, right);
144 PHP_EXP_NODE *make_known_const(char *name)
146 int const_id = -1;
147 if ( g_known_const.count(name) ) {
148 const_id = g_known_const[name];
150 return make_const_exp_dnum(const_id);
154 // Create function parameter (in declaration)
156 PHP_EXP_NODE *make_func_param(PHP_EXP_NODE *list, PHP_EXP_NODE *var_exp_node, char *class_name, int byref)
158 PHP_FUNC_PARAM_DEF *param = new PHP_FUNC_PARAM_DEF;
159 memset(param, 0, sizeof(PHP_FUNC_PARAM_DEF));
161 param->si_var = var_exp_node->var_si_node;
162 param->si_var->type = PHP_SCOPE_PARAM;
163 //printf("mark %p->%p as param\n", param->si_var, param->si_var->var);
165 param->var = param->si_var->var;
167 delete var_exp_node;
168 param->class_name = class_name ? strdup(class_name) : 0;
169 param->byref = byref;
171 PHP_EXP_NODE *curr_node = make_const_exp_int_obj(param);
173 if ( list ) {
174 PHP_EXP_NODE *p = list;
175 while ( p->next) {
176 p = p->next;
178 p->next = curr_node;
179 return list;
180 } else {
181 return curr_node;
186 * Syntax tree generation
188 PHP_SYN_NODE *make_expr_syn_node(PHP_STATMENT_TYPE type, PHP_EXP_NODE *expr)
190 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
191 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
193 syn_node->type = type;
194 syn_node->node_expr = expr;
196 return syn_node;
199 PHP_SYN_NODE *make_ifelse_syn_node(PHP_EXP_NODE *expr,
200 PHP_SYN_NODE *then_node, PHP_SYN_NODE *elseif_list, PHP_SYN_NODE *else_node)
202 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
203 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
205 syn_node->type = PHP_ST_IF;
206 syn_node->node_if.cond = expr;
207 syn_node->node_if.code_if = then_node;
209 if ( elseif_list ) {
210 syn_node->node_if.code_else = elseif_list;
212 PHP_SYN_NODE *curr_if = elseif_list;
213 while ( curr_if->node_if.code_else ) {
214 curr_if = curr_if->node_if.code_else;
216 curr_if->node_if.code_else = else_node;
217 } else {
218 syn_node->node_if.code_else = else_node;
220 return syn_node;
223 PHP_SYN_NODE *make_while_loop_syn_node(PHP_EXP_NODE *cond, PHP_SYN_NODE *code, int do_while)
225 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
226 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
228 syn_node->type = do_while ? PHP_ST_WHILE : PHP_ST_DO_WHILE;
229 syn_node->node_while.cond = cond;
230 syn_node->node_while.code = code;
232 return syn_node;
235 PHP_SYN_NODE *make_for_syn_node(PHP_EXP_NODE *start, PHP_EXP_NODE *cond,
236 PHP_EXP_NODE *next, PHP_SYN_NODE *code)
238 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
239 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
241 syn_node->type = PHP_ST_FOR;
242 syn_node->node_for.do_start = start;
243 syn_node->node_for.cond = cond;
244 syn_node->node_for.do_next = next;
245 syn_node->node_for.code = code;
247 return syn_node;
250 PHP_SYN_NODE *make_foreach_loop_syn_node(PHP_EXP_NODE *elems,
251 PHP_EXP_NODE *i_key, PHP_EXP_NODE *i_val, PHP_SYN_NODE *code, int byref)
253 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
254 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
256 syn_node->type = PHP_ST_FOREACH;
257 syn_node->node_foreach.elems = elems;
258 syn_node->node_foreach.code = code;
259 syn_node->node_foreach.i_key = i_key ? i_key->var_si_node : 0;
260 syn_node->node_foreach.i_val = i_val->var_si_node;
261 syn_node->node_foreach.byref = byref;
263 if ( i_key ) {
264 delete i_key;
266 delete i_val;
268 return syn_node;
271 PHP_SYN_NODE *make_func_decl_syn_node(const char *name, PHP_EXP_NODE *param_list)
273 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
274 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
276 syn_node->type = PHP_ST_FUNC_DECL;
278 syn_node->func_decl = new PHP_SYN_FUNC_DECL_NODE;
279 memset(syn_node->func_decl, 0, sizeof(PHP_SYN_FUNC_DECL_NODE));
280 syn_node->func_decl->name = strdup(name);
282 if ( param_list ) {
283 PHP_EXP_NODE *curr_param = param_list;
284 // count parameters first
285 while ( curr_param ) {
286 syn_node->func_decl->param_count++;
287 curr_param = curr_param->next;
289 syn_node->func_decl->params = new PHP_FUNC_PARAM_DEF[syn_node->func_decl->param_count];
290 curr_param = param_list;
291 for(int i = 0; param_list; param_list = param_list->next, i++) {
292 syn_node->func_decl->params[i] = *(PHP_FUNC_PARAM_DEF *)param_list->val_node.ptr_val;
293 // param has been copied to array, so it's no longer needed
294 delete (PHP_FUNC_PARAM_DEF *)param_list->val_node.ptr_val;
296 // dispose linked list as well
297 while ( curr_param ) {
298 PHP_EXP_NODE *p = curr_param->next;
299 delete curr_param;
300 curr_param = p;
304 return syn_node;
307 PHP_SYN_NODE *make_class_decl_syn_node()
309 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
310 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
312 syn_node->type = PHP_ST_CLASS_DECL;
314 syn_node->class_decl = new PHP_SYN_CLASS_DECL_NODE;
315 memset(syn_node->class_decl, 0, sizeof(PHP_SYN_CLASS_DECL_NODE));
317 return syn_node;
320 PHP_SYN_NODE *make_switch_syn_node(PHP_EXP_NODE *cond, PHP_EXP_NODE *case_list)
322 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
323 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
325 syn_node->type = PHP_ST_SWITCH;
328 // Bind all statement lists into single one for
329 // simplier execution
331 PHP_SYN_NODE *stat_list_tail = 0;
332 for(PHP_EXP_NODE *cur_case = case_list; cur_case; cur_case = cur_case->next) {
333 PHP_SYN_NODE *cur_stat_list = cur_case->exp_node->tree_node.syn_right;
334 if ( stat_list_tail ) {
335 while ( stat_list_tail->next_node ) stat_list_tail = stat_list_tail->next_node;
336 stat_list_tail->next_node = cur_stat_list;
337 } else {
338 stat_list_tail = cur_stat_list;
342 syn_node->node_switch.cond = cond;
343 syn_node->node_switch.case_list = case_list;
345 return syn_node;
348 PHP_VAR_NODE *make_var_node()
350 PHP_VAR_NODE *node = new PHP_VAR_NODE;
351 memset(node, 0, sizeof(PHP_VAR_NODE));
352 node->value.type = PHP_VAL_NONE;
354 return node;
357 PHP_VAR_NODE *make_array_var()
359 PHP_VAR_NODE *node = make_var_node();
360 cast_value_array(&node->value);
362 return node;
366 * Called from lexer when ${IDENT} is recognized
368 PHP_EXP_NODE *get_var_node(const char *name)
370 PHP_EXP_NODE *node = make_zero_exp_node();
371 node->op = PHP_OP_VAR;
373 PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, name);
374 if ( si ) {
375 if ( (si->type == PHP_SCOPE_VAR) || (si->type == PHP_SCOPE_PARAM) ) {
376 node->var_si_node = si;
377 } else {
379 // Error: symbol already defined as different entity
381 php_report_error(PHP_ERROR,
382 "symbol [%s] already defined as different entity (%d)", name, si->type);
384 } else {
385 add_var_2_scope(g_current_scope, make_var_node(), name);
386 node->var_si_node = get_scope_item(g_current_scope, name);
389 return node;
392 void free_var_node(PHP_VAR_NODE *v)
394 delete v;
398 * Init function scope table before transferring control there.
399 * 1. Evaluate all by-value params
400 * 2. Lvalue-evaluate all by-ref params and adjust pointers
402 void func_scope_init(PHP_FUNC_PARAM_DEF *params, int param_count,
403 PHP_SCOPE_TABLE_TYPE * /*scope_map*/, PHP_VALUE_NODE *arg_array,
404 std::map<std::string, PHP_VAR_NODE *> &saved_vars)
407 // Step 1: save origival vars
408 PHP_SCOPE_TABLE_TYPE *curr_scope_map = (PHP_SCOPE_TABLE_TYPE *)g_current_scope;
409 for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();++i) {
410 if ( (i->second->type == PHP_SCOPE_VAR) || (i->second->type == PHP_SCOPE_PARAM) ) {
411 if ( !(i->second->var->flags & PHP_VARFLAG_STATIC) ) {
412 //printf("Saving %s = %p->%p\n", i->first.c_str(), i->second, i->second->var);
413 saved_vars[i->first] = i->second->var;
418 // Step 2: calculate new values of call parameters
419 PHP_VAR_NODE *call_params[PHP_MAX_FUNC_PARAM];
420 for(int i = 0; i < param_count; i++) {
421 PHP_VAR_NODE *curr_arg_val = array_get_by_int_key(arg_array, i);
422 if ( curr_arg_val->value.type != PHP_VAL_NONE ) {
423 if ( (curr_arg_val->flags & PHP_VARFLAG_BYREF) || params[i].byref ) {
424 call_params[i] = php_expr_eval_lvalue((PHP_EXP_NODE *)curr_arg_val->value.ptr_val);
425 if ( !call_params[i] ) {
426 php_report_error(PHP_ERROR, "Byref parameter is not lvalue");
427 return;
429 } else {
430 call_params[i] = make_var_node();
431 call_params[i]->ref_count = 1;
432 //printf("alloc var for callparam %d -> %p\n", i, call_params[i]);
433 php_expr_eval((PHP_EXP_NODE *)curr_arg_val->value.ptr_val, &call_params[i]->value);
435 } else {
436 // put default value
437 php_report_error(PHP_WARNING, "Default parameters are not implemented yet");
438 call_params[i] = make_var_node();
439 call_params[i]->ref_count = 1;
443 // Step 3: assign new values to call parameters
444 for(int i = 0; i < param_count; i++) {
445 //printf("assign new param si=%p var=%p -> %p\n", params[i].si_var, params[i].si_var->var, call_params[i]);
446 params[i].si_var->var = call_params[i];
450 // Step 4: allocate new stack local vars
451 for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();++i) {
452 if ( !((i->second->type == PHP_SCOPE_PARAM) || (i->second->type == PHP_SCOPE_VAR)) ) {
453 continue;
455 //printf("in scope: %p %s [ %s ] with flags %02x\n", i->second, i->second->type == PHP_SCOPE_PARAM ? "param" : "var",
456 // i->first.c_str(), i->second->var->flags);
457 if ( !(i->second->var->flags & PHP_VARFLAG_STATIC) && (i->second->type != PHP_SCOPE_PARAM) ) {
458 //printf("alloc new for %s [ %p->%p ]\n", i->first.c_str(), i->second, i->second->var);
459 i->second->var = make_var_node();
460 i->second->var->ref_count = 1;
466 * Since by-ref params changes pointers in scope table, we need to restore them
467 * to original objects, so:
468 * 1. Memory will not leak
469 * 2. Next call may be using same params by-value, so it need independent varnode
471 void func_scope_copy_back(PHP_FUNC_PARAM_DEF *params, int param_count,
472 PHP_SCOPE_TABLE_TYPE * /*scope_map*/, PHP_VALUE_NODE *arg_array,
473 std::map<std::string, PHP_VAR_NODE *> &saved_vars)
476 if ( param_count < array_get_size(arg_array) ) {
477 param_count = array_get_size(arg_array);
480 PHP_VAR_NODE *call_params[PHP_MAX_FUNC_PARAM];
481 int call_param_2free_count = 0;
482 for(int i = 0; i < param_count; i++) {
483 PHP_VAR_NODE *curr_arg_val = array_get_by_int_key(arg_array, i);
484 if ( !((curr_arg_val->flags & PHP_VARFLAG_BYREF) || params[i].byref) ) {
485 //printf("Delete param %d %p->%p\n", i, params[i].si_var, params[i].si_var->var);
486 call_params[call_param_2free_count++] = params[i].si_var->var;
488 params[i].si_var->var = params[i].var;
491 PHP_SCOPE_TABLE_TYPE *curr_scope_map = (PHP_SCOPE_TABLE_TYPE *)g_current_scope;
492 for(PHP_SCOPE_TABLE_TYPE::iterator i = curr_scope_map->begin(); i != curr_scope_map->end();++i) {
493 if ( (i->second->type == PHP_SCOPE_VAR) || (i->second->type == PHP_SCOPE_PARAM) ) {
494 if ( !(i->second->var->flags & PHP_VARFLAG_STATIC) ) {
495 //printf("Restoring %s = %p->%p\n", i->first.c_str(), i->second, i->second->var);
496 //assert(saved_vars[i->first]);
497 if (i->second->type == PHP_SCOPE_VAR) {
498 value_value_free(&i->second->var->value);
499 delete i->second->var;
501 i->second->var = saved_vars[i->first];
505 for(int i = 0; i < call_param_2free_count; i++) {
506 value_value_free(&call_params[i]->value);
507 delete call_params[i];
511 PHP_SCOPE_TABLE make_scope_table()
513 PHP_SCOPE_TABLE_TYPE *scope_map = new PHP_SCOPE_TABLE_TYPE;
515 return scope_map;
518 void switch_push_scope_table(PHP_SCOPE_TABLE new_table)
520 PHP_SCOPE_STACK_TYPE *scope_stack = (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
521 scope_stack->push_back((PHP_SCOPE_TABLE_TYPE *)g_current_scope);
522 g_current_scope = new_table;
525 void switch_pop_scope_table(int old_free)
527 PHP_SCOPE_STACK_TYPE *scope_stack = (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
528 if ( old_free ) {
529 delete_scope_table(g_current_scope);
531 if ( scope_stack->size() == 0 ) {
532 php_report_error(PHP_INTERNAL_ERROR, "Stack underrun - no valid scope");
534 g_current_scope = scope_stack->back();
535 scope_stack->pop_back();
538 void delete_scope_table(PHP_SCOPE_TABLE scope)
540 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
542 for(PHP_SCOPE_TABLE_TYPE::iterator i = scope_map->begin(); i != scope_map->end();++i) {
543 switch ( i->second->type ) {
544 case PHP_SCOPE_PARAM:
545 //break;
546 case PHP_SCOPE_VAR: {
547 //printf("removing %s\n", i->first.c_str());
548 PHP_VAR_NODE *var = i->second->var;
549 var_node_free(var);
551 break;
552 case PHP_SCOPE_FUNC: {
553 PHP_SYN_NODE *func = i->second->func;
554 php_syn_tree_free(func);
556 break;
557 case PHP_SCOPE_CLASS: {
558 PHP_SYN_NODE *class_decl = i->second->class_decl;
559 php_syn_tree_free(class_decl);
561 break;
562 case PHP_SCOPE_NONE:
563 php_report_error(PHP_INTERNAL_ERROR, "Scope table can not have such items");
564 break;
566 delete i->second;
568 delete scope_map;
571 void add_func_2_scope(PHP_SCOPE_TABLE scope, PHP_SYN_NODE *func)
573 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
574 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
575 it->type = PHP_SCOPE_FUNC;
576 it->func = func;
577 std::string key(func->func_decl->name);
578 if ( scope_map->count(key) ) {
579 // error - function already defined
580 php_report_error(PHP_ERROR, "Can not add function to scope table - already present");
581 } else {
582 (*scope_map)[key] = it;
586 void add_class_2_scope(PHP_SCOPE_TABLE scope, PHP_SYN_NODE *class_node)
588 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
589 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
590 it->type = PHP_SCOPE_CLASS;
591 it->class_decl = class_node;
592 std::string key(class_node->class_decl->name);
593 if ( scope_map->count(key) ) {
594 // error - function already defined
595 php_report_error(PHP_ERROR, "Can not add function to scope table - already present");
596 } else {
597 (*scope_map)[key] = it;
601 PHP_SCOPE_ITEM *make_named_scope_item(PHP_SCOPE_TABLE scope, const char *name)
603 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
604 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
605 memset(it, 0, sizeof(PHP_SCOPE_ITEM));
607 std::string key(name);
608 (*scope_map)[key] = it;
609 return it;
612 PHP_SCOPE_ITEM *add_var_2_scope(PHP_SCOPE_TABLE scope, PHP_VAR_NODE *var, const char *name)
614 PHP_SCOPE_ITEM *it = make_named_scope_item(scope, name);
615 it->type = PHP_SCOPE_VAR;
616 it->var = var;
617 var->ref_count++;
618 return it;
621 PHP_SCOPE_ITEM_TYPE get_scope_item_type(PHP_SCOPE_TABLE scope, const char *name)
623 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
624 std::string key(name);
625 if ( scope_map->count(key) ) {
626 PHP_SCOPE_ITEM *it = (*scope_map)[key];
627 return it->type;
629 return PHP_SCOPE_NONE;
632 PHP_SCOPE_ITEM *get_scope_item(PHP_SCOPE_TABLE scope, const char *name)
634 assert(name);
635 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
636 std::string key(name);
637 if ( scope_map->count(key) ) {
638 PHP_SCOPE_ITEM *it = (*scope_map)[key];
639 return it;
641 return 0;
644 const char *get_scope_var_name(PHP_SCOPE_TABLE scope, PHP_VAR_NODE *var)
646 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
648 for(PHP_SCOPE_TABLE_TYPE::iterator i = scope_map->begin(); i != scope_map->end();++i) {
649 if ( i->second->type == PHP_SCOPE_VAR ) {
650 PHP_VAR_NODE *curr_var = i->second->var;
651 if ( curr_var == var ) {
652 return i->first.c_str();
656 return 0;
660 /* array operations */
661 const std::string &array_get_ith_key(PHP_VALUE_NODE *array, int i)
663 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
664 PHP_ARRAY_ITER_TYPE it = arr_ptr->array.begin();
665 while(i--) ++it;
666 return it->first;
670 PHP_VAR_NODE *array_get_by_str_key(PHP_VALUE_NODE *array, std::string key)
672 if ( array->type != PHP_VAL_ARRAY ) {
673 return 0;
675 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
676 if ( arr_ptr->array.count(key) ) {
677 return (arr_ptr->array)[key];
678 } else {
679 PHP_VAR_NODE *add_node = make_var_node();
680 add_node->value.type = PHP_VAL_NONE;
681 add_node->ref_count++;
682 (arr_ptr->array)[key] = add_node;
683 arr_ptr->sorted_keys.push_back(key);
684 return add_node;
688 PHP_VAR_NODE *array_get_by_int_key(PHP_VALUE_NODE *array, int key)
690 if ( array->type != PHP_VAL_ARRAY ) {
691 return 0;
693 char s_key[32];
694 snprintf(s_key, sizeof(s_key), "%d", key);
695 return array_get_by_str_key(array, s_key);
698 PHP_VAR_NODE *array_get_by_key(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key)
700 if ( array->type != PHP_VAL_ARRAY ) {
701 return 0;
703 PHP_VALUE_NODE s_key = *key;
704 cast_value_str(&s_key);
705 return array_get_by_str_key(array, s_key.str_val);
708 void array_set_by_key(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key, PHP_VAR_NODE *node)
710 if ( array->type != PHP_VAL_ARRAY ) {
711 return;
713 PHP_VALUE_NODE s_key = *key;
714 cast_value_str(&s_key);
715 array_remove_at_str_key(array, s_key.str_val);
716 array_add_to_str_key(array, s_key.str_val, node);
717 value_value_free(&s_key);
720 void array_add_to_str_key(PHP_VALUE_NODE *array, std::string key, PHP_VAR_NODE *node)
722 if ( array->type != PHP_VAL_ARRAY ) {
723 return ;
725 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
726 if ( !arr_ptr->array.count(key) ) {
727 node->ref_count++;
728 (arr_ptr->array)[key] = node;
729 arr_ptr->sorted_keys.push_back(key);
733 void array_remove_at_str_key(PHP_VALUE_NODE *array, std::string key)
735 if ( array->type != PHP_VAL_ARRAY ) {
736 return ;
738 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
739 if ( arr_ptr->array.count(key) ) {
740 PHP_VAR_NODE *node = (arr_ptr->array)[key];
741 var_node_free(node);
742 arr_ptr->array.erase(key);
743 for(PHP_ARRAY_KEY_ITER_TYPE i = arr_ptr->sorted_keys.begin(); i != arr_ptr->sorted_keys.end(); ++i) {
744 if ( *i == key ) {
745 arr_ptr->sorted_keys.erase(i);
746 break;
752 void array_add_to_int_key(PHP_VALUE_NODE *array, int key, PHP_VAR_NODE *node)
754 char s_key[32];
755 snprintf(s_key, sizeof(s_key), "%d", key);
756 array_add_to_str_key(array, s_key, node);
760 int array_is_key_here(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key)
762 if ( array->type != PHP_VAL_ARRAY ) {
763 return 0;
765 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
766 PHP_VALUE_NODE s_key = *key;
767 cast_value_str(&s_key);
768 std::string arr_key(s_key.str_val);
770 return arr_ptr->array.count(arr_key);
773 int array_get_size(PHP_VALUE_NODE *array)
775 if ( array->type != PHP_VAL_ARRAY ) {
776 return 0;
778 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
780 return arr_ptr->array.size();
783 PHP_VAR_NODE *array_push_back(PHP_VALUE_NODE *array)
785 for(int i = 0; i < 0xffff;i++) {
786 PHP_VAR_NODE *arr_var_node = array_get_by_int_key(array, i);
787 if ( arr_var_node->value.type == PHP_VAL_NONE ) {
788 return arr_var_node;
791 // array size reached 64K ?!
792 return 0;
795 /* value manipulation - assignment and disposal */
797 void value_value_assign(PHP_VALUE_NODE *dst, PHP_VALUE_NODE *src)
799 // first, free old value
800 value_value_free(dst);
801 dst->type = src->type;
802 switch(src->type) {
803 // scalars are copied. Objects are copied too, since
804 // interpreter doesn't allocate them.
805 case PHP_VAL_NONE:
806 case PHP_VAL_BOOL:
807 case PHP_VAL_INT:
808 case PHP_VAL_FLOAT:
809 case PHP_VAL_OBJECT:
810 // assign biggest in union
811 dst->obj_val = src->obj_val;
812 break;
813 // string is duplicated
814 case PHP_VAL_STRING: {
815 dst->str_val = strdup(src->str_val);
816 break;
818 // array must duplicate all it's values
819 case PHP_VAL_ARRAY: {
820 dst->ptr_val = new PHP_ARRAY_TYPE;
821 PHP_ARRAY_TYPE *src_array = (PHP_ARRAY_TYPE *)src->ptr_val;
822 for(PHP_ARRAY_KEY_ITER_TYPE i = src_array->sorted_keys.begin(); i != src_array->sorted_keys.end(); ++i) {
823 PHP_VAR_NODE *added = array_get_by_str_key(dst, *i);
824 value_value_assign(&added->value, &src_array->array[*i]->value);
826 break;
829 case PHP_VAL_VAR_NODE:
830 case PHP_VAL_INT_DATA: break;
834 void var_node_free(PHP_VAR_NODE *var)
836 assert(var && var->ref_count);
837 var->ref_count--;
838 if ( var->ref_count == 0 ) {
839 value_value_free(&var->value);
840 delete var;
844 void value_value_free(PHP_VALUE_NODE *val)
846 switch(val->type) {
847 case PHP_VAL_NONE:
848 case PHP_VAL_BOOL:
849 case PHP_VAL_INT:
850 case PHP_VAL_FLOAT:
851 break;
852 case PHP_VAL_STRING: {
853 free(val->str_val);
854 val->str_val = 0;
855 break;
857 case PHP_VAL_ARRAY: {
858 for(PHP_ARRAY_ITER_TYPE i = ((PHP_ARRAY_TYPE *)val->ptr_val)->array.begin();
859 i != ((PHP_ARRAY_TYPE *)val->ptr_val)->array.end(); ++i) {
860 PHP_VAR_NODE *var_i = i->second;
861 var_node_free(var_i);
863 delete ((PHP_ARRAY_TYPE *)val->ptr_val);
864 break;
866 case PHP_VAL_OBJECT: break;
868 case PHP_VAL_VAR_NODE:
869 case PHP_VAL_INT_DATA: break;
871 val->type = PHP_VAL_NONE;
874 /* casting functions */
875 void cast_value_dnum(PHP_VALUE_NODE *val)
877 switch(val->type) {
878 case PHP_VAL_NONE: val->int_val = 0; break;
879 case PHP_VAL_BOOL:
880 case PHP_VAL_INT: break;
881 case PHP_VAL_FLOAT: val->int_val = (int)val->float_val; break;
882 case PHP_VAL_STRING: {
883 char *str = val->str_val;
884 val->int_val = atoll(val->str_val);
885 free(str);
886 break;
888 case PHP_VAL_ARRAY:
889 case PHP_VAL_OBJECT: val->int_val = 0; break;
890 case PHP_VAL_VAR_NODE:
891 case PHP_VAL_INT_DATA: assert(0); break;
893 val->type = PHP_VAL_INT;
896 void cast_value_bool(PHP_VALUE_NODE *val)
898 cast_value_dnum(val);
899 val->type = PHP_VAL_BOOL;
902 void cast_value_fnum(PHP_VALUE_NODE *val)
904 switch(val->type) {
905 case PHP_VAL_NONE: val->float_val = 0; break;
906 case PHP_VAL_BOOL:
907 case PHP_VAL_INT: val->float_val = val->int_val; break;
908 case PHP_VAL_FLOAT: break;
909 case PHP_VAL_STRING: {
910 char *str = val->str_val;
911 val->float_val = atof(val->str_val);
912 free(str);
913 break;
915 case PHP_VAL_ARRAY:
916 case PHP_VAL_OBJECT: val->float_val = 0; break;
917 case PHP_VAL_VAR_NODE:
918 case PHP_VAL_INT_DATA: assert(0); break;
920 val->type = PHP_VAL_FLOAT;
923 void cast_value_str(PHP_VALUE_NODE *val)
925 char buff[256];
926 switch(val->type) {
927 case PHP_VAL_NONE: buff[0] = 0; break;
928 case PHP_VAL_BOOL:
929 case PHP_VAL_INT: snprintf(buff, sizeof(buff), "%" PRIu64, val->int_val); break;
930 case PHP_VAL_FLOAT: snprintf(buff, sizeof(buff), "%.02f", val->float_val); break;
931 case PHP_VAL_STRING: return;
932 case PHP_VAL_ARRAY: {
933 delete ((PHP_ARRAY_TYPE *)val->ptr_val);
934 strcpy(buff, "Array"); break;
936 case PHP_VAL_OBJECT: strcpy(buff, "Object"); break;
937 case PHP_VAL_VAR_NODE:
938 case PHP_VAL_INT_DATA: assert(0); break;
940 val->str_val = strdup(buff);
941 val->type = PHP_VAL_STRING;
944 void cast_value_array(PHP_VALUE_NODE *val)
946 switch(val->type) {
947 case PHP_VAL_NONE:
948 case PHP_VAL_BOOL:
949 case PHP_VAL_INT:
950 case PHP_VAL_FLOAT: break;
951 case PHP_VAL_STRING: free(val->str_val);
952 case PHP_VAL_ARRAY: return;
953 case PHP_VAL_OBJECT: ;/* must call to free_obj() */
954 case PHP_VAL_VAR_NODE:
955 case PHP_VAL_INT_DATA: assert(0); break;
957 val->ptr_val = new PHP_ARRAY_TYPE;
958 val->type = PHP_VAL_ARRAY;
962 * Function calls
964 PHP_EXP_NODE *make_func_call_exp(char *func_name, PHP_EXP_NODE *args)
966 PHP_EXP_NODE *call_node = make_zero_exp_node();
968 call_node->op = PHP_OP_FUNC_CALL;
969 // copy function name
970 call_node->tree_node.left = make_zero_exp_node();
971 call_node->tree_node.left->op = PHP_OP_VAL;
972 call_node->tree_node.left->val_node.type = PHP_VAL_STRING;
973 call_node->tree_node.left->val_node.str_val = strdup(func_name);
974 // set params
975 call_node->tree_node.right = args;
977 return call_node;
980 PHP_EXP_NODE *make_func_call_param_list()
982 PHP_VAR_NODE *params = make_array_var();
984 PHP_EXP_NODE *exp_node = make_zero_exp_node();
986 exp_node->op = PHP_OP_VAR;
987 exp_node->var_node = params;
989 return exp_node;
992 void func_call_add_expr(PHP_VAR_NODE *paramlist, PHP_EXP_NODE *arg, int byref)
994 PHP_VAR_NODE *node = array_push_back(&paramlist->value);
995 node->value.type = PHP_VAL_INT_DATA;
996 node->value.ptr_val = arg;
997 if ( byref ) {
998 node->flags |= PHP_VARFLAG_BYREF;
1002 void php_add_native_func(PHP_BLTIN_FUNC_DEF *def)
1004 if ( get_scope_item_type(g_global_scope, def->name) != PHP_SCOPE_NONE ) {
1006 // Error: something already defined by this name
1008 php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined");
1009 return;
1011 PHP_SCOPE_TABLE func_scope = make_scope_table();
1013 PHP_SYN_NODE *decl_node = make_func_decl_syn_node(def->name, 0);
1014 decl_node->func_decl->param_count = def->param_count;
1015 decl_node->func_decl->params = new PHP_FUNC_PARAM_DEF[def->param_count];
1018 // Built-in functions don't have class specifier, and can handle
1019 // default arguments internally
1021 memset(decl_node->func_decl->params, 0, sizeof(PHP_FUNC_PARAM_DEF) * def->param_count);
1022 for(int i = 0; i < def->param_count;i++) {
1023 PHP_VAR_NODE *func_param = make_var_node();
1024 char param_name[32];
1025 snprintf(param_name, sizeof(param_name), "__param_%d", i);
1027 decl_node->func_decl->params[i].def_value.type = PHP_VAL_NONE;
1028 decl_node->func_decl->params[i].var = func_param;
1029 decl_node->func_decl->params[i].si_var = add_var_2_scope(func_scope, func_param, param_name);
1030 decl_node->func_decl->params[i].si_var->type = PHP_SCOPE_PARAM;
1032 decl_node->func_decl->scope = func_scope;
1033 decl_node->func_decl->is_native = 1;
1034 decl_node->func_decl->native_ptr = def->func;
1036 add_func_2_scope(g_global_scope, decl_node);
1039 void php_add_native_class(const char *name, PHP_NATIVE_PROP_GET_FUNC_PTR prop_get_native_ptr)
1041 if ( get_scope_item_type(g_global_scope, name) != PHP_SCOPE_NONE ) {
1043 // Error: something already defined by this name
1045 php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined");
1046 return;
1048 PHP_SYN_NODE *decl_node = make_class_decl_syn_node();
1049 decl_node->class_decl->name = strdup(name);
1050 decl_node->class_decl->is_native = 1;
1051 decl_node->class_decl->native_prop_get_ptr = prop_get_native_ptr;
1052 add_class_2_scope(g_global_scope, decl_node);
1055 void php_engine_init()
1057 g_global_scope = make_scope_table();
1059 g_current_scope = g_global_scope;
1061 g_scope_stack = new PHP_SCOPE_STACK_TYPE;
1063 // here built-in functions/objects/vars are loaded
1064 php_init_core_lib();
1065 php_init_amule_lib();
1068 void php_exp_tree_free(PHP_EXP_NODE *tree)
1070 if ( !tree ) {
1071 return;
1073 switch ( tree->op ) {
1074 case PHP_OP_VAR:
1075 /* will be deleted during scope table destruction */
1076 break;
1077 case PHP_OP_VAL:
1078 value_value_free(&tree->val_node);
1079 break;
1080 case PHP_OP_FUNC_CALL: {
1081 php_exp_tree_free(tree->tree_node.left);
1082 PHP_VAR_NODE *args = tree->tree_node.right->var_node;
1083 PHP_VALUE_NODE *args_array = &args->value;
1084 for(PHP_ARRAY_ITER_TYPE i = ((PHP_ARRAY_TYPE *)args_array->ptr_val)->array.begin();
1085 i != ((PHP_ARRAY_TYPE *)args_array->ptr_val)->array.end(); ++i) {
1086 PHP_VAR_NODE *var_i = i->second;
1087 php_exp_tree_free((PHP_EXP_NODE *)var_i->value.ptr_val);
1089 value_value_free(&args->value);
1090 delete tree->tree_node.right->var_node;
1091 delete tree->tree_node.right;
1093 break;
1094 case PHP_OP_ARRAY: {
1095 PHP_EXP_NODE *curr = tree->tree_node.left;
1096 while (curr) {
1097 PHP_EXP_NODE *next = curr->next;
1098 php_exp_tree_free(curr->exp_node);
1099 delete curr;
1100 curr = next;
1103 break;
1104 case PHP_OP_MUX:
1105 php_exp_tree_free(tree->exp_node);
1106 default:
1107 // all other things using left/right
1108 php_exp_tree_free(tree->tree_node.left);
1109 php_exp_tree_free(tree->tree_node.right);
1112 delete tree;
1115 void php_syn_tree_free(PHP_SYN_NODE *tree)
1117 while ( tree ) {
1118 switch ( tree->type ) {
1119 case PHP_ST_EXPR:
1120 case PHP_ST_RET:
1121 php_exp_tree_free(tree->node_expr);
1122 break;
1123 case PHP_ST_ECHO: {
1124 PHP_EXP_NODE *curr = tree->node_expr;
1125 while (curr) {
1126 PHP_EXP_NODE *next = curr->next;
1127 php_exp_tree_free(curr->exp_node);
1128 delete curr;
1129 curr = next;
1132 break;
1133 case PHP_ST_IF:
1134 php_exp_tree_free(tree->node_if.cond);
1135 php_syn_tree_free(tree->node_if.code_if);
1136 php_syn_tree_free(tree->node_if.code_else);
1137 break;
1138 case PHP_ST_WHILE:
1139 case PHP_ST_DO_WHILE:
1140 php_exp_tree_free(tree->node_while.cond);
1141 php_syn_tree_free(tree->node_while.code);
1142 break;
1143 case PHP_ST_FOR:
1144 php_exp_tree_free(tree->node_for.do_start);
1145 php_exp_tree_free(tree->node_for.cond);
1146 php_exp_tree_free(tree->node_for.do_next);
1147 php_syn_tree_free(tree->node_for.code);
1148 break;
1149 case PHP_ST_FOREACH:
1150 php_exp_tree_free(tree->node_foreach.elems);
1151 php_syn_tree_free(tree->node_foreach.code);
1152 break;
1153 case PHP_ST_CONTINUE:
1154 case PHP_ST_BREAK:
1155 break;
1156 case PHP_ST_FUNC_DECL:
1157 if ( !tree->func_decl->is_native ) {
1158 php_syn_tree_free(tree->func_decl->code);
1160 delete_scope_table(tree->func_decl->scope);
1161 free(tree->func_decl->name);
1162 for(int i = 0; i < tree->func_decl->param_count; i++) {
1163 if (tree->func_decl->params[i].class_name) {
1164 free(tree->func_decl->params[i].class_name);
1167 delete [] tree->func_decl->params;
1168 delete tree->func_decl;
1169 break;
1170 case PHP_ST_SWITCH: {
1171 php_exp_tree_free(tree->node_switch.cond);
1172 php_syn_tree_free(tree->node_switch.case_list->exp_node->tree_node.syn_right);
1173 PHP_EXP_NODE *curr = tree->node_switch.case_list;
1174 while (curr) {
1175 PHP_EXP_NODE *next = curr->next;
1176 if ( curr->exp_node ) {
1177 php_exp_tree_free(curr->exp_node->tree_node.left);
1178 delete curr->exp_node;
1180 delete curr;
1181 curr = next;
1184 break;
1185 case PHP_ST_CLASS_DECL:
1186 free(tree->class_decl->name);
1187 delete tree->class_decl;
1188 break;
1190 PHP_SYN_NODE *next_node = tree->next_node;
1191 delete tree;
1192 tree = next_node;
1196 void php_engine_free()
1198 if ( g_global_scope ) {
1199 delete_scope_table(g_global_scope);
1201 php_syn_tree_free(g_syn_tree_top);
1202 g_global_scope = 0;
1203 g_current_scope = 0;
1204 delete (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
1208 * Create reference. This is recoursive process, since operators []
1209 * can be stacked: $a[1][2][3] = & $b;
1210 * There's 3 valid cases in making reference:
1211 * 1,2. Target is scalar variable or variable by name ${xxx}
1212 * 3. Target is member of array.
1214 void exp_set_ref(PHP_EXP_NODE *expr, PHP_VAR_NODE *var, PHP_VALUE_NODE *key)
1216 switch ( expr->op ) {
1217 case PHP_OP_VAR: {
1218 if ( expr->var_si_node->var != var ) {
1219 if ( key ) {
1220 cast_value_array(&expr->var_si_node->var->value);
1221 array_set_by_key(&expr->var_si_node->var->value, key, var);
1222 } else {
1223 var_node_free(expr->var_si_node->var);
1224 expr->var_si_node->var = var;
1225 var->ref_count++;
1229 break;
1230 case PHP_OP_ARRAY_BY_KEY: {
1231 PHP_VALUE_NODE i_key;
1232 i_key.type = PHP_VAL_NONE;
1233 php_expr_eval(expr->tree_node.right, &i_key);
1234 exp_set_ref(expr->tree_node.left, var, &i_key);
1236 break;
1237 default:
1238 php_report_error(PHP_ERROR, "Bad left part of operator =&: (%d)",
1239 expr->tree_node.left->op);
1244 * This is heart of expression tree: evaluation. It's split into 2 functions
1245 * where 1 evaluates "value" of expression, and other evaluates "lvalue" i.e. assignable
1246 * entity from given subtree.
1249 void php_expr_eval(PHP_EXP_NODE *expr, PHP_VALUE_NODE *result)
1251 PHP_VALUE_NODE result_val_right, result_val_left;
1252 PHP_VAR_NODE *lval_node = 0;
1253 PHP_SCOPE_ITEM *si = 0;
1254 result_val_right.type = PHP_VAL_NONE;
1255 result_val_left.type = PHP_VAL_NONE;
1256 switch(expr->op) {
1257 case PHP_OP_VAL:
1258 if ( result ) {
1259 value_value_assign(result, &expr->val_node);
1261 break;
1262 case PHP_OP_VAR:
1263 if ( result ) {
1264 value_value_assign(result, &expr->var_si_node->var->value);
1266 break;
1267 case PHP_OP_ASS:
1268 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1269 if ( !lval_node ) {
1270 break;
1272 php_expr_eval(expr->tree_node.right, &lval_node->value);
1273 if ( result ) {
1274 value_value_assign(result, &lval_node->value);
1276 break;
1277 case PHP_OP_ARRAY_BY_KEY:
1278 php_expr_eval(expr->tree_node.right, &result_val_right);
1279 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1280 cast_value_array(&lval_node->value);
1281 cast_value_str(&result_val_right);
1282 lval_node = array_get_by_key(&lval_node->value, &result_val_right);
1283 if ( result ) {
1284 value_value_assign(result, &lval_node->value);
1286 break;
1287 case PHP_MAKE_REF:
1288 lval_node = php_expr_eval_lvalue(expr->tree_node.right);
1289 if ( !lval_node ) {
1290 break;
1292 exp_set_ref(expr->tree_node.left, lval_node, 0);
1293 break;
1294 case PHP_OP_ARRAY:
1295 if ( result ) {
1296 PHP_EXP_NODE *curr = expr->tree_node.left;
1297 value_value_free(result);
1298 cast_value_array(result);
1299 while ( curr ) {
1300 switch( curr->exp_node->op ) {
1301 case PHP_OP_ARRAY_PAIR:
1302 if ( curr->exp_node->tree_node.right ) {
1303 php_expr_eval(curr->exp_node->tree_node.left, &result_val_left);
1304 cast_value_str(&result_val_left);
1305 lval_node = array_get_by_key(result, &result_val_left);
1306 value_value_free(&result_val_left);
1307 php_expr_eval(curr->exp_node->tree_node.right, &lval_node->value);
1308 } else {
1309 lval_node = array_push_back(result);
1310 php_expr_eval(curr->exp_node->tree_node.left, &lval_node->value);
1312 break;
1313 case PHP_OP_ARRAY_REF_PAIR:
1314 lval_node = php_expr_eval_lvalue(curr->exp_node->tree_node.right);
1315 break;
1316 default:
1317 php_report_error(PHP_INTERNAL_ERROR, "Array list contain wrong node");
1318 return;
1320 curr = curr->next;
1323 break;
1324 case PHP_OP_FUNC_CALL:
1325 php_run_func_call(expr, result);
1326 break;
1327 case PHP_OP_LIST: {
1328 PHP_EXP_NODE *curr = expr;
1329 while ( curr ) {
1330 if ( curr->exp_node ) {
1331 php_expr_eval(curr->exp_node, result);
1333 curr = curr->next;
1336 break;
1337 case PHP_OP_CAT:
1338 php_expr_eval(expr->tree_node.right, &result_val_right);
1339 php_expr_eval(expr->tree_node.left, &result_val_left);
1340 if ( result ) {
1341 cast_value_str(&result_val_left);
1342 cast_value_str(&result_val_right);
1343 value_value_free(result);
1344 result->type = PHP_VAL_STRING;
1345 // using "malloc" and not "new" since all strings are freed
1346 // later with "free" and not "delete"
1347 result->str_val = (char *)malloc(strlen(result_val_left.str_val) +
1348 strlen(result_val_right.str_val) + 1);
1349 strcpy(result->str_val, result_val_left.str_val);
1350 strcat(result->str_val, result_val_right.str_val);
1352 break;
1353 case PHP_OP_MUX:
1354 php_expr_eval(expr->exp_node, &result_val_right);
1355 cast_value_bool(&result_val_right);
1356 if ( result_val_right.int_val ) {
1357 php_expr_eval(expr->tree_node.left, result);
1358 } else {
1359 php_expr_eval(expr->tree_node.right, result);
1361 break;
1362 case PHP_OP_CAST_INT:
1363 if ( result ) {
1364 php_expr_eval(expr->tree_node.left, result);
1365 cast_value_dnum(result);
1367 break;
1368 case PHP_OP_CAST_FLOAT:
1369 if ( result ) {
1370 php_expr_eval(expr->tree_node.left, result);
1371 cast_value_fnum(result);
1373 break;
1374 case PHP_OP_CAST_BOOL:
1375 if ( result ) {
1376 php_expr_eval(expr->tree_node.left, result);
1377 cast_value_bool(result);
1379 break;
1380 case PHP_OP_CAST_STR:
1381 if ( result ) {
1382 php_expr_eval(expr->tree_node.left, result);
1383 cast_value_str(result);
1385 break;
1386 case PHP_OP_LOG_NOT:
1387 if ( result ) {
1388 php_expr_eval(expr->tree_node.left, &result_val_right);
1389 cast_value_bool(&result_val_right);
1390 result_val_right.int_val = !result_val_right.int_val;
1391 value_value_assign(result, &result_val_right);
1393 break;
1394 case PHP_OP_NOT:
1395 if ( result ) {
1396 php_expr_eval(expr->tree_node.left, &result_val_right);
1397 cast_value_bool(&result_val_right);
1398 result_val_right.int_val = ~result_val_right.int_val;
1399 value_value_assign(result, &result_val_right);
1401 break;
1402 case PHP_OP_ADD:
1403 case PHP_OP_SUB:
1404 case PHP_OP_MUL:
1405 case PHP_OP_DIV:
1406 php_expr_eval(expr->tree_node.right, &result_val_right);
1407 php_expr_eval(expr->tree_node.left, &result_val_left);
1408 if ( result ) {
1409 php_eval_simple_math(expr->op, &result_val_left, &result_val_right, result);
1411 break;
1412 case PHP_OP_SHL:
1413 case PHP_OP_SHR:
1414 case PHP_OP_OR:
1415 case PHP_OP_AND:
1416 case PHP_OP_XOR:
1417 case PHP_OP_LOG_OR:
1418 case PHP_OP_LOG_AND:
1419 case PHP_OP_LOG_XOR:
1420 php_expr_eval(expr->tree_node.right, &result_val_right);
1421 php_expr_eval(expr->tree_node.left, &result_val_left);
1422 if ( result ) {
1423 php_eval_int_math(expr->op, &result_val_left, &result_val_right, result);
1425 break;
1426 case PHP_OP_EQ:
1427 case PHP_OP_NEQ:
1428 case PHP_OP_GRT:
1429 case PHP_OP_LWR:
1430 php_expr_eval(expr->tree_node.right, &result_val_right);
1431 php_expr_eval(expr->tree_node.left, &result_val_left);
1432 if ( result ) {
1433 php_eval_compare(expr->op, &result_val_left, &result_val_right, result);
1435 break;
1436 case PHP_OP_PRINT:
1437 php_expr_eval(expr->tree_node.left, &result_val_right);
1438 cast_value_str(&result_val_right);
1440 // I print to buffer
1441 CPhPLibContext::Print(result_val_right.str_val);
1442 break;
1443 case PHP_OP_OBJECT_DEREF: // $x->y
1444 // take variable from scope of current object
1445 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1446 if ( !lval_node ) {
1447 php_report_error(PHP_ERROR, "Left part of -> must be lvalue");
1448 return;
1450 if ( lval_node->value.type != PHP_VAL_OBJECT ) {
1451 php_report_error(PHP_ERROR, "Left part of -> must be an object");
1452 return;
1454 if ( get_scope_item_type(g_global_scope, lval_node->value.obj_val.class_name) == PHP_SCOPE_NONE ) {
1455 php_report_error(PHP_ERROR, "Undeclared object");
1456 return;
1458 si = get_scope_item(g_global_scope, lval_node->value.obj_val.class_name);
1459 if ( si->type != PHP_SCOPE_CLASS ) {
1460 php_report_error(PHP_INTERNAL_ERROR, "Object classname is not name of class");
1461 return;
1463 // left part is ok, let's check the right
1464 if ( (expr->tree_node.right->op != PHP_OP_VAL) || (expr->tree_node.right->val_node.type != PHP_VAL_STRING) ) {
1465 php_report_error(PHP_ERROR, "Right part of -> must be string value");
1466 return;
1468 if ( si->class_decl->class_decl->is_native ) {
1469 si->class_decl->class_decl->native_prop_get_ptr(lval_node->value.obj_val.inst_ptr,
1470 expr->tree_node.right->val_node.str_val, result);
1471 } else {
1472 php_report_error(PHP_ERROR, "Only native classes supported");
1473 return;
1475 break;
1476 case PHP_OP_CLASS_DEREF: // A::y
1477 // take variable (static) from scope of current class
1478 php_report_error(PHP_ERROR, "Value of static class members not supported");
1479 break;
1480 default: ;
1483 value_value_free(&result_val_left);
1484 value_value_free(&result_val_right);
1487 PHP_VAR_NODE *php_expr_eval_lvalue(PHP_EXP_NODE *expr)
1489 PHP_VAR_NODE *lval_node = 0;
1491 PHP_VALUE_NODE index;
1492 index.type = PHP_VAL_NONE;
1494 switch(expr->op) {
1495 case PHP_OP_VAR:
1496 lval_node = expr->var_si_node->var;
1497 break;
1498 case PHP_OP_ARRAY_BY_KEY:
1499 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1500 if ( !lval_node ) {
1501 break;
1504 cast_value_array(&lval_node->value);
1505 if ( expr->tree_node.right ) {
1506 php_expr_eval(expr->tree_node.right, &index);
1507 if ( index.type == PHP_VAL_NONE ) {
1508 // something got wrong: evaluation result is not a value
1509 return 0;
1511 cast_value_str(&index);
1512 lval_node = array_get_by_key(&lval_node->value, &index);
1513 value_value_free(&index);
1514 } else {
1515 // this is "$xxx[] = " construct.
1516 lval_node = array_push_back(&lval_node->value);
1518 case PHP_OP_VAR_BY_EXP: // ${"xxx"}
1519 // should take variable from current scope
1520 break;
1521 case PHP_OP_OBJECT_DEREF: // $x->y
1522 // take variable from scope of current object
1523 php_report_error(PHP_ERROR, "Assign to class members not supported");
1524 break;
1525 case PHP_OP_CLASS_DEREF: // A::y
1526 // take variable (static) from scope of current class
1527 php_report_error(PHP_ERROR, "Assign to static class members not supported");
1528 break;
1529 default:
1531 // Error: expression can not be taken as lvalue
1533 php_report_error(PHP_ERROR, "This expression can't be used as lvalue");
1535 return lval_node;
1538 PHP_VALUE_TYPE cast_type_resolve(PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2)
1540 if ( (op1->type == PHP_VAL_FLOAT) || (op2->type == PHP_VAL_FLOAT) ) {
1541 cast_value_fnum(op1);
1542 cast_value_fnum(op2);
1543 return PHP_VAL_FLOAT;
1544 } else {
1545 cast_value_dnum(op1);
1546 cast_value_dnum(op2);
1547 return PHP_VAL_INT;
1552 * Same as simple_math, but result is always bool
1554 void php_eval_compare(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1556 result->type = PHP_VAL_BOOL;
1557 if ( (op1->type == PHP_VAL_STRING) || (op2->type == PHP_VAL_STRING) ) {
1558 cast_value_str(op1);
1559 cast_value_str(op2);
1560 int cmp_val = strcmp(op1->str_val, op2->str_val);
1561 switch(op) {
1562 case PHP_OP_EQ:
1563 result->int_val = (cmp_val == 0);
1564 break;
1565 case PHP_OP_NEQ:
1566 result->int_val = (cmp_val != 0);
1567 break;
1568 case PHP_OP_GRT:
1569 result->int_val = (cmp_val > 0);
1570 break;
1571 case PHP_OP_LWR:
1572 result->int_val = (cmp_val < 0);
1573 break;
1574 case PHP_OP_GRT_EQ:
1575 result->int_val = (cmp_val >= 0);
1576 break;
1577 case PHP_OP_LWR_EQ:
1578 result->int_val = (cmp_val <= 0);
1579 break;
1580 default:
1581 php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op");
1583 } else {
1584 PHP_VALUE_TYPE restype = cast_type_resolve(op1, op2);
1585 switch(op) {
1586 case PHP_OP_EQ:
1587 if ( restype == PHP_VAL_FLOAT ) {
1588 result->int_val = op1->float_val == op2->float_val;
1589 } else {
1590 result->int_val = op1->int_val == op2->int_val;
1592 break;
1593 case PHP_OP_NEQ:
1594 if ( restype == PHP_VAL_FLOAT ) {
1595 result->int_val = op1->float_val != op2->float_val;
1596 } else {
1597 result->int_val = op1->int_val != op2->int_val;
1599 break;
1600 case PHP_OP_GRT:
1601 if ( restype == PHP_VAL_FLOAT ) {
1602 result->int_val = op1->float_val > op2->float_val;
1603 } else {
1604 result->int_val = op1->int_val > op2->int_val;
1606 break;
1607 case PHP_OP_GRT_EQ:
1608 if ( restype == PHP_VAL_FLOAT ) {
1609 result->int_val = op1->float_val >= op2->float_val;
1610 } else {
1611 result->int_val = op1->int_val >= op2->int_val;
1613 break;
1614 case PHP_OP_LWR:
1615 if ( restype == PHP_VAL_FLOAT ) {
1616 result->int_val = op1->float_val < op2->float_val;
1617 } else {
1618 result->int_val = op1->int_val < op2->int_val;
1620 break;
1621 case PHP_OP_LWR_EQ:
1622 if ( restype == PHP_VAL_FLOAT ) {
1623 result->int_val = op1->float_val <= op2->float_val;
1624 } else {
1625 result->int_val = op1->int_val <= op2->int_val;
1627 break;
1628 default:
1629 php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op");
1634 void php_eval_simple_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1636 result->type = cast_type_resolve(op1, op2);
1637 switch(op) {
1638 case PHP_OP_ADD:
1639 if ( result->type == PHP_VAL_FLOAT ) {
1640 result->float_val = op1->float_val + op2->float_val;
1641 } else {
1642 result->int_val = op1->int_val + op2->int_val;
1644 break;
1645 case PHP_OP_SUB:
1646 if ( result->type == PHP_VAL_FLOAT ) {
1647 result->float_val = op1->float_val - op2->float_val;
1648 } else {
1649 result->int_val = op1->int_val - op2->int_val;
1651 break;
1652 case PHP_OP_MUL:
1653 if ( result->type == PHP_VAL_FLOAT ) {
1654 result->float_val = op1->float_val * op2->float_val;
1655 } else {
1656 result->int_val = op1->int_val * op2->int_val;
1658 break;
1659 case PHP_OP_DIV:
1660 if ( result->type == PHP_VAL_FLOAT ) {
1661 result->float_val = op1->float_val / op2->float_val;
1662 } else {
1663 result->int_val = op1->int_val / op2->int_val;
1665 break;
1666 default:
1667 php_report_error(PHP_INTERNAL_ERROR, "This op is not simple math");
1671 void php_eval_int_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1673 cast_value_dnum(op1);
1674 cast_value_dnum(op2);
1675 result->type = PHP_VAL_INT;
1676 switch(op) {
1677 case PHP_OP_SHL:
1678 result->int_val = op1->int_val << op2->int_val;
1679 break;
1680 case PHP_OP_SHR:
1681 result->int_val = op1->int_val >> op2->int_val;
1682 break;
1683 case PHP_OP_OR:
1684 result->int_val = op1->int_val | op2->int_val;
1685 break;
1686 case PHP_OP_LOG_OR:
1687 result->int_val = op1->int_val || op2->int_val;
1688 break;
1689 case PHP_OP_AND:
1690 result->int_val = op1->int_val & op2->int_val;
1691 break;
1692 case PHP_OP_LOG_AND:
1693 result->int_val = op1->int_val && op2->int_val;
1694 break;
1695 case PHP_OP_LOG_XOR:
1696 op1->int_val = op1->int_val ? 1 : 0;
1697 op2->int_val = op2->int_val ? 1 : 0;
1698 case PHP_OP_XOR:
1699 result->int_val = op1->int_val ^ op2->int_val;
1700 break;
1701 default:
1702 php_report_error(PHP_INTERNAL_ERROR, "This op is not int math");
1707 // left = VAR(func_name), right=ARRAY(args)
1708 void php_run_func_call(PHP_EXP_NODE *node, PHP_VALUE_NODE *result)
1710 PHP_EXP_NODE *l_node = node->tree_node.left;
1711 PHP_EXP_NODE *r_node = node->tree_node.right;
1712 if ( (l_node->op != PHP_OP_VAL) || (l_node->val_node.type != PHP_VAL_STRING) ||
1713 (r_node->op != PHP_OP_VAR) || (r_node->var_node->value.type != PHP_VAL_ARRAY) ) {
1715 // Internal error: function name must be string value node, and
1716 // params must be an array
1718 php_report_error(PHP_INTERNAL_ERROR, "Function call node have wrong data");
1719 return ;
1721 PHP_SCOPE_ITEM *si = get_scope_item(g_global_scope, l_node->val_node.str_val);
1722 if ( !si ) {
1724 // Error: undeclared symbol
1726 php_report_error(PHP_ERROR, "Function [ %s ] is not defined", l_node->val_node.str_val);
1727 return;
1729 if ( si->type != PHP_SCOPE_FUNC) {
1731 // Error: defined, but wrong type !
1733 php_report_error(PHP_ERROR, "Item [ %s ] is not a function", l_node->val_node.str_val);
1734 return;
1736 PHP_SYN_NODE *func = si->func;
1737 if ( func->type != PHP_ST_FUNC_DECL ) {
1739 // Internal error: node not a function
1741 php_report_error(PHP_INTERNAL_ERROR, "Wrong type in function decl node");
1742 return;
1746 // Switch stack and call function
1749 PHP_SYN_FUNC_DECL_NODE *func_decl = func->func_decl;
1751 std::map<std::string, PHP_VAR_NODE *> saved_vars;
1752 func_scope_init(func_decl->params, func_decl->param_count,
1753 (PHP_SCOPE_TABLE_TYPE *)func_decl->scope,
1754 &r_node->var_node->value, saved_vars);
1756 switch_push_scope_table((PHP_SCOPE_TABLE_TYPE *)func_decl->scope);
1758 if ( func_decl->is_native ) {
1759 func_decl->native_ptr(result);
1760 } else {
1761 php_execute(func_decl->code, result);
1765 // restore stack, free arg list
1767 switch_pop_scope_table(0);
1768 func_scope_copy_back(func_decl->params, func_decl->param_count,
1769 (PHP_SCOPE_TABLE_TYPE *)func_decl->scope, &r_node->var_node->value, saved_vars);
1771 //scope_reset_nonstatics(func_decl->scope);
1776 * Theoretically speaking this function must run on generated code. On the
1777 * practical side - I need it to debug syntax tree generation. Later, it can
1778 * be changes to generate code for some kind of bytecode for stack machine
1780 int php_execute(PHP_SYN_NODE *node, PHP_VALUE_NODE *result)
1782 if ( !node ) {
1783 return 0;
1785 int curr_exec_result;
1786 while ( node ) {
1787 curr_exec_result = 0;
1788 PHP_VALUE_NODE cond_result;
1789 cond_result.type = PHP_VAL_NONE;
1790 switch (node->type) {
1791 case PHP_ST_EXPR:
1792 php_expr_eval(node->node_expr, 0);
1793 break;
1794 case PHP_ST_IF:
1795 php_expr_eval(node->node_if.cond, &cond_result);
1796 cast_value_bool(&cond_result);
1797 if ( cond_result.int_val ) {
1798 if ( node->node_if.code_if ) {
1799 curr_exec_result = php_execute(node->node_if.code_if, result);
1801 } else {
1802 if ( node->node_if.code_else ) {
1803 curr_exec_result = php_execute(node->node_if.code_else, result);
1806 break;
1807 case PHP_ST_RET:
1808 if ( node->node_expr ) {
1809 php_expr_eval(node->node_expr, result);
1811 if ( node->next_node ) {
1813 // Warning: code after "return" statement
1815 php_report_error(PHP_WARNING, "code after 'return'");
1817 // "return" is ultimate "break"
1818 curr_exec_result = -0xffff;
1819 break;
1820 case PHP_ST_ECHO: {
1821 PHP_EXP_NODE *curr = node->node_expr;
1822 while (curr) {
1823 php_expr_eval(curr->exp_node, &cond_result);
1824 cast_value_str(&cond_result);
1825 CPhPLibContext::Print(cond_result.str_val);
1826 value_value_free(&cond_result);
1827 curr = curr->next;
1830 break;
1831 case PHP_ST_CONTINUE:
1832 case PHP_ST_BREAK:
1833 if ( node->node_expr ) {
1834 // 'break' or 'continue' used with an argument
1835 php_expr_eval(node->node_expr, &cond_result);
1836 } else {
1837 // without an argument break or continue just 1 loop
1838 cond_result.type = PHP_VAL_INT;
1839 cond_result.int_val = 1;
1841 cast_value_dnum(&cond_result);
1842 if ( node->type == PHP_ST_BREAK ) {
1843 curr_exec_result = -(int)(cond_result.int_val);
1844 } else {
1845 curr_exec_result = cond_result.int_val;
1847 break;
1849 case PHP_ST_WHILE:
1850 case PHP_ST_DO_WHILE:
1851 if ( node->type == PHP_ST_WHILE ) {
1852 php_expr_eval(node->node_while.cond, &cond_result);
1853 cast_value_bool(&cond_result);
1854 } else {
1855 cond_result.int_val = 1;
1857 while ( cond_result.int_val ) {
1858 // evaluate code within while loop
1859 curr_exec_result = php_execute(node->node_while.code, 0);
1860 // if 'break' was used
1861 if ( curr_exec_result < 0 ) {
1862 // decrease number of loops to break
1863 curr_exec_result++;
1864 // and break current loop
1865 break;
1867 // normal execution of loop or continue
1868 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1869 curr_exec_result = 0;
1870 // evaluate 'while' loop conditions
1871 php_expr_eval(node->node_while.cond, &cond_result);
1872 cast_value_bool(&cond_result);
1874 // if 'continue' was used with an argument > 1
1875 if ( curr_exec_result > 1 ) {
1876 // decrease number of loops to skip
1877 curr_exec_result--;
1878 // and break current loop
1879 break;
1882 break;
1883 case PHP_ST_FOR:
1884 php_expr_eval(node->node_for.do_start, &cond_result);
1885 php_expr_eval(node->node_for.cond, &cond_result);
1886 cast_value_bool(&cond_result);
1887 while ( cond_result.int_val ) {
1888 curr_exec_result = php_execute(node->node_for.code, 0);
1889 // handle 'break' and 'continue'
1890 if ( curr_exec_result < 0 ) {
1891 curr_exec_result++;
1892 break;
1894 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1895 curr_exec_result = 0;
1896 // evaluate 'for' loop conditions
1897 php_expr_eval(node->node_for.do_next, &cond_result);
1898 php_expr_eval(node->node_for.cond, &cond_result);
1899 cast_value_bool(&cond_result);
1901 if ( curr_exec_result > 1 ) {
1902 curr_exec_result--;
1903 break;
1906 break;
1907 case PHP_ST_FOREACH: {
1908 PHP_VAR_NODE *elems = php_expr_eval_lvalue(node->node_foreach.elems);
1909 if ( !elems || (elems->value.type != PHP_VAL_ARRAY) ) {
1910 php_report_error(PHP_ERROR, "Argument of 'foreach' must be array");
1911 break;
1913 PHP_ARRAY_TYPE *array = (PHP_ARRAY_TYPE *)elems->value.ptr_val;
1914 PHP_SCOPE_ITEM *i_key = node->node_foreach.i_key;
1915 // keys in array are string values.
1916 if ( i_key ) {
1917 i_key->var->value.type = PHP_VAL_STRING;
1919 PHP_SCOPE_ITEM *i_val = node->node_foreach.i_val;
1920 array->current = array->sorted_keys.begin();
1921 while ( array->current != array->sorted_keys.end() ) {
1922 if ( i_key ) {
1923 PHP_VALUE_NODE tmp_val;
1924 tmp_val.type = PHP_VAL_STRING;
1925 tmp_val.str_val = (char *)array->current->c_str();
1926 value_value_assign(&i_key->var->value, &tmp_val);
1928 PHP_VALUE_NODE *curr_value = &array->array[*array->current]->value;
1929 value_value_assign(&i_val->var->value, curr_value);
1930 curr_exec_result = php_execute(node->node_foreach.code, 0);
1931 // clean up
1932 if ( i_key ) {
1933 value_value_free(&i_key->var->value);
1935 if ( node->node_foreach.byref ) {
1936 value_value_assign(curr_value, &i_val->var->value);
1938 value_value_free(&i_val->var->value);
1939 // handle 'break' and 'continue'
1940 if ( curr_exec_result < 0 ) {
1941 curr_exec_result++;
1942 break;
1944 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1945 curr_exec_result = 0;
1946 // next element
1947 array->current++;
1949 if ( curr_exec_result > 1 ) {
1950 curr_exec_result--;
1951 break;
1955 break;
1956 case PHP_ST_SWITCH: {
1957 PHP_SYN_NODE *cur_exec = 0;
1958 // evaluate switch argument
1959 php_expr_eval(node->node_switch.cond, &cond_result);
1960 // loop through list of case statements
1961 PHP_EXP_NODE *curr = node->node_switch.case_list;
1962 while (curr) {
1963 PHP_VALUE_NODE cur_value, cmp_result;
1964 cur_value.type = cmp_result.type = PHP_VAL_NONE;
1965 // TODO make amuleweb not crash when 'default' is used
1966 php_expr_eval(curr->exp_node->tree_node.left, &cur_value);
1968 // switch argument equal to case argument?
1969 php_eval_compare(PHP_OP_EQ, &cur_value, &cond_result, &cmp_result);
1970 if ( cmp_result.int_val ) {
1971 // execute code and rest of case statements
1972 cur_exec = static_cast<PHP_SYN_NODE *>(curr->exp_node->tree_node.syn_right);
1973 break;
1975 curr = curr->next;
1977 if ( cur_exec ) {
1978 curr_exec_result = php_execute(cur_exec, result);
1979 // break
1980 if (curr_exec_result < 0) curr_exec_result++;
1981 // continue
1982 if (curr_exec_result > 0) curr_exec_result--;
1985 break;
1986 default: ;
1988 if ( curr_exec_result ) {
1989 return curr_exec_result;
1991 node = node->next_node;
1993 // everything ok, keep going
1994 return 0;
1999 // call it when something gone wrong
2001 void php_report_error(PHP_MSG_TYPE err_type, const char *msg, ...)
2004 // hope my error message will never be that big.
2006 // security is ok, since _user_ errors are not reporting thru
2007 // this function, but handled by scipt itself.
2008 // However, badly written script MAY force user-supplied data to
2009 // leak here and create stack overrun exploit. Be warned.
2011 char msgbuf[1024];
2012 const char *type_msg = 0;
2013 switch(err_type) {
2014 case PHP_MESAGE:
2015 type_msg = "PHP:";
2016 break;
2017 case PHP_WARNING:
2018 type_msg = "PHP Warning:";
2019 break;
2020 case PHP_ERROR:
2021 type_msg = "PHP Error:";
2022 break;
2023 case PHP_INTERNAL_ERROR:
2024 type_msg = "PHP Internal Error:";
2025 break;
2028 va_list args;
2029 va_start(args, msg);
2030 vsnprintf(msgbuf, sizeof(msgbuf), msg, args);
2031 va_end(args);
2033 printf("%s %s\n", type_msg, msgbuf);
2034 assert(err_type != PHP_INTERNAL_ERROR);
2038 int phperror(char *s)
2040 printf("ERROR in grammar %s after [%s] near line %d\n", s, phptext, phplineno);
2041 return 0;
2044 // File_checked_for_headers