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.
10 //
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.
15 //
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.
20 //
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
24 //
25
26
27 #include <string> // Do_not_auto_remove (g++-4.0.1)
28
29 #ifdef PHP_STANDALONE_EN
30 #include <map>
31 #include <list>
32 #include <stdarg.h>
33 #else
34 #include "WebServer.h"
35 #endif
36
37
38 #include "php_syntree.h"
39 #include "php_core_lib.h"
40
41
42 PHP_SYN_NODE *g_syn_tree_top = 0;
43
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;
48
49
50 //
51 // Known named constant values
52 std::map<std::string, int> g_known_const;
53
make_zero_exp_node()54 static PHP_EXP_NODE *make_zero_exp_node()
55 {
56 PHP_EXP_NODE *node = new PHP_EXP_NODE;
57 memset(node, 0, sizeof(PHP_EXP_NODE));
58 return node;
59 }
60
make_const_exp_dnum(int number)61 PHP_EXP_NODE *make_const_exp_dnum(int number)
62 {
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;
67
68 return node;
69 }
70
make_const_exp_fnum(float number)71 PHP_EXP_NODE *make_const_exp_fnum(float number)
72 {
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;
77
78 return node;
79 }
80
make_const_exp_str(char * s,int unescape)81 PHP_EXP_NODE *make_const_exp_str(char *s, int unescape)
82 {
83 PHP_EXP_NODE *node = make_zero_exp_node();
84 node->op = PHP_OP_VAL;
85 node->val_node.type = PHP_VAL_STRING;
86
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;
97 }
98 } else {
99 *p++ = *s++;
100 }
101 }
102 *p = 0;
103 } else {
104 node->val_node.str_val = strdup(s);
105 }
106
107 return node;
108 }
109
make_const_exp_int_obj(void * obj)110 PHP_EXP_NODE *make_const_exp_int_obj(void *obj)
111 {
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;
116
117 return node;
118 }
119
make_exp_1(PHP_EXP_OP op,PHP_EXP_NODE * operand)120 PHP_EXP_NODE *make_exp_1(PHP_EXP_OP op, PHP_EXP_NODE *operand)
121 {
122 PHP_EXP_NODE *node = make_zero_exp_node();
123 node->op = op;
124 node->tree_node.left = operand;
125 return node;
126 }
127
make_exp_2(PHP_EXP_OP op,PHP_EXP_NODE * left,PHP_EXP_NODE * right)128 PHP_EXP_NODE *make_exp_2(PHP_EXP_OP op, PHP_EXP_NODE *left, PHP_EXP_NODE *right)
129 {
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;
135 }
136
make_exp_2_self(PHP_EXP_OP op,PHP_EXP_NODE * self,PHP_EXP_NODE * right)137 PHP_EXP_NODE *make_exp_2_self(PHP_EXP_OP op, PHP_EXP_NODE *self, PHP_EXP_NODE *right)
138 {
139 PHP_EXP_NODE *clone_self = make_zero_exp_node();
140 *clone_self = *self;
141 return make_exp_2(op, clone_self, right);
142 }
143
make_known_const(char * name)144 PHP_EXP_NODE *make_known_const(char *name)
145 {
146 int const_id = -1;
147 if ( g_known_const.count(name) ) {
148 const_id = g_known_const[name];
149 }
150 return make_const_exp_dnum(const_id);
151 }
152
153 //
154 // Create function parameter (in declaration)
155 //
make_func_param(PHP_EXP_NODE * list,PHP_EXP_NODE * var_exp_node,char * class_name,int byref)156 PHP_EXP_NODE *make_func_param(PHP_EXP_NODE *list, PHP_EXP_NODE *var_exp_node, char *class_name, int byref)
157 {
158 PHP_FUNC_PARAM_DEF *param = new PHP_FUNC_PARAM_DEF;
159 memset(param, 0, sizeof(PHP_FUNC_PARAM_DEF));
160
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);
164
165 param->var = param->si_var->var;
166
167 delete var_exp_node;
168 param->class_name = class_name ? strdup(class_name) : 0;
169 param->byref = byref;
170
171 PHP_EXP_NODE *curr_node = make_const_exp_int_obj(param);
172
173 if ( list ) {
174 PHP_EXP_NODE *p = list;
175 while ( p->next) {
176 p = p->next;
177 }
178 p->next = curr_node;
179 return list;
180 } else {
181 return curr_node;
182 }
183 }
184
185 /*
186 * Syntax tree generation
187 */
make_expr_syn_node(PHP_STATMENT_TYPE type,PHP_EXP_NODE * expr)188 PHP_SYN_NODE *make_expr_syn_node(PHP_STATMENT_TYPE type, PHP_EXP_NODE *expr)
189 {
190 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
191 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
192
193 syn_node->type = type;
194 syn_node->node_expr = expr;
195
196 return syn_node;
197 }
198
make_ifelse_syn_node(PHP_EXP_NODE * expr,PHP_SYN_NODE * then_node,PHP_SYN_NODE * elseif_list,PHP_SYN_NODE * else_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)
201 {
202 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
203 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
204
205 syn_node->type = PHP_ST_IF;
206 syn_node->node_if.cond = expr;
207 syn_node->node_if.code_if = then_node;
208
209 if ( elseif_list ) {
210 syn_node->node_if.code_else = elseif_list;
211
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;
215 }
216 curr_if->node_if.code_else = else_node;
217 } else {
218 syn_node->node_if.code_else = else_node;
219 }
220 return syn_node;
221 }
222
make_while_loop_syn_node(PHP_EXP_NODE * cond,PHP_SYN_NODE * code,int do_while)223 PHP_SYN_NODE *make_while_loop_syn_node(PHP_EXP_NODE *cond, PHP_SYN_NODE *code, int do_while)
224 {
225 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
226 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
227
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;
231
232 return syn_node;
233 }
234
make_for_syn_node(PHP_EXP_NODE * start,PHP_EXP_NODE * cond,PHP_EXP_NODE * next,PHP_SYN_NODE * code)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)
237 {
238 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
239 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
240
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;
246
247 return syn_node;
248 }
249
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)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)
252 {
253 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
254 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
255
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;
262
263 if ( i_key ) {
264 delete i_key;
265 }
266 delete i_val;
267
268 return syn_node;
269 }
270
make_func_decl_syn_node(const char * name,PHP_EXP_NODE * param_list)271 PHP_SYN_NODE *make_func_decl_syn_node(const char *name, PHP_EXP_NODE *param_list)
272 {
273 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
274 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
275
276 syn_node->type = PHP_ST_FUNC_DECL;
277
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);
281
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;
288 }
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;
295 }
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;
301 }
302 }
303
304 return syn_node;
305 }
306
make_class_decl_syn_node()307 PHP_SYN_NODE *make_class_decl_syn_node()
308 {
309 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
310 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
311
312 syn_node->type = PHP_ST_CLASS_DECL;
313
314 syn_node->class_decl = new PHP_SYN_CLASS_DECL_NODE;
315 memset(syn_node->class_decl, 0, sizeof(PHP_SYN_CLASS_DECL_NODE));
316
317 return syn_node;
318 }
319
make_switch_syn_node(PHP_EXP_NODE * cond,PHP_EXP_NODE * case_list)320 PHP_SYN_NODE *make_switch_syn_node(PHP_EXP_NODE *cond, PHP_EXP_NODE *case_list)
321 {
322 PHP_SYN_NODE *syn_node = new PHP_SYN_NODE;
323 memset(syn_node, 0, sizeof(PHP_SYN_NODE));
324
325 syn_node->type = PHP_ST_SWITCH;
326
327 //
328 // Bind all statement lists into single one for
329 // simplier execution
330 //
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;
339 }
340 }
341
342 syn_node->node_switch.cond = cond;
343 syn_node->node_switch.case_list = case_list;
344
345 return syn_node;
346 }
347
make_var_node()348 PHP_VAR_NODE *make_var_node()
349 {
350 PHP_VAR_NODE *node = new PHP_VAR_NODE;
351 memset(node, 0, sizeof(PHP_VAR_NODE));
352 node->value.type = PHP_VAL_NONE;
353
354 return node;
355 }
356
make_array_var()357 PHP_VAR_NODE *make_array_var()
358 {
359 PHP_VAR_NODE *node = make_var_node();
360 cast_value_array(&node->value);
361
362 return node;
363 }
364
365 /*
366 * Called from lexer when ${IDENT} is recognized
367 */
get_var_node(const char * name)368 PHP_EXP_NODE *get_var_node(const char *name)
369 {
370 PHP_EXP_NODE *node = make_zero_exp_node();
371 node->op = PHP_OP_VAR;
372
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 {
378 //
379 // Error: symbol already defined as different entity
380 //
381 php_report_error(PHP_ERROR,
382 "symbol [%s] already defined as different entity (%d)", name, si->type);
383 }
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);
387 }
388
389 return node;
390 }
391
free_var_node(PHP_VAR_NODE * v)392 void free_var_node(PHP_VAR_NODE *v)
393 {
394 delete v;
395 }
396
397 /*
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
401 */
func_scope_init(PHP_FUNC_PARAM_DEF * params,int param_count,PHP_SCOPE_TABLE_TYPE *,PHP_VALUE_NODE * arg_array,std::map<std::string,PHP_VAR_NODE * > & saved_vars)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)
405 {
406 //
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;
414 }
415 }
416 }
417 //
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;
428 }
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);
434 }
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;
440 }
441 }
442 //
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];
447 }
448
449 //
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;
454 }
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;
461 }
462 }
463 }
464
465 /*
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
470 */
func_scope_copy_back(PHP_FUNC_PARAM_DEF * params,int param_count,PHP_SCOPE_TABLE_TYPE *,PHP_VALUE_NODE * arg_array,std::map<std::string,PHP_VAR_NODE * > & saved_vars)471 static 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)
474 {
475 /*
476 if ( param_count < array_get_size(arg_array) ) {
477 param_count = array_get_size(arg_array);
478 }
479 */
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;
487 }
488 params[i].si_var->var = params[i].var;
489 }
490
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;
500 }
501 i->second->var = saved_vars[i->first];
502 }
503 }
504 }
505 for(int i = 0; i < call_param_2free_count; i++) {
506 value_value_free(&call_params[i]->value);
507 delete call_params[i];
508 }
509 }
510
make_scope_table()511 PHP_SCOPE_TABLE make_scope_table()
512 {
513 PHP_SCOPE_TABLE_TYPE *scope_map = new PHP_SCOPE_TABLE_TYPE;
514
515 return scope_map;
516 }
517
switch_push_scope_table(PHP_SCOPE_TABLE new_table)518 void switch_push_scope_table(PHP_SCOPE_TABLE new_table)
519 {
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;
523 }
524
switch_pop_scope_table(int old_free)525 void switch_pop_scope_table(int old_free)
526 {
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);
530 }
531 if ( scope_stack->size() == 0 ) {
532 php_report_error(PHP_INTERNAL_ERROR, "Stack underrun - no valid scope");
533 }
534 g_current_scope = scope_stack->back();
535 scope_stack->pop_back();
536 }
537
delete_scope_table(PHP_SCOPE_TABLE scope)538 void delete_scope_table(PHP_SCOPE_TABLE scope)
539 {
540 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
541
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);
550 }
551 break;
552 case PHP_SCOPE_FUNC: {
553 PHP_SYN_NODE *func = i->second->func;
554 php_syn_tree_free(func);
555 }
556 break;
557 case PHP_SCOPE_CLASS: {
558 PHP_SYN_NODE *class_decl = i->second->class_decl;
559 php_syn_tree_free(class_decl);
560 }
561 break;
562 case PHP_SCOPE_NONE:
563 php_report_error(PHP_INTERNAL_ERROR, "Scope table can not have such items");
564 break;
565 }
566 delete i->second;
567 }
568 delete scope_map;
569 }
570
add_func_2_scope(PHP_SCOPE_TABLE scope,PHP_SYN_NODE * func)571 void add_func_2_scope(PHP_SCOPE_TABLE scope, PHP_SYN_NODE *func)
572 {
573 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
574 std::string key(func->func_decl->name);
575 if ( scope_map->count(key) ) {
576 // error - function already defined
577 php_report_error(PHP_ERROR, "Can not add function to scope table - already present");
578 } else {
579 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
580 it->type = PHP_SCOPE_FUNC;
581 it->func = func;
582 (*scope_map)[key] = it;
583 }
584 }
585
add_class_2_scope(PHP_SCOPE_TABLE scope,PHP_SYN_NODE * class_node)586 void add_class_2_scope(PHP_SCOPE_TABLE scope, PHP_SYN_NODE *class_node)
587 {
588 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
589 std::string key(class_node->class_decl->name);
590 if ( scope_map->count(key) ) {
591 // error - function already defined
592 php_report_error(PHP_ERROR, "Can not add function to scope table - already present");
593 } else {
594 PHP_SCOPE_ITEM *it = new PHP_SCOPE_ITEM;
595 it->type = PHP_SCOPE_CLASS;
596 it->class_decl = class_node;
597 (*scope_map)[key] = it;
598 }
599 }
600
make_named_scope_item(PHP_SCOPE_TABLE scope,const char * name)601 static PHP_SCOPE_ITEM *make_named_scope_item(PHP_SCOPE_TABLE scope, const char *name)
602 {
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));
606
607 std::string key(name);
608 (*scope_map)[key] = it;
609 return it;
610 }
611
add_var_2_scope(PHP_SCOPE_TABLE scope,PHP_VAR_NODE * var,const char * name)612 PHP_SCOPE_ITEM *add_var_2_scope(PHP_SCOPE_TABLE scope, PHP_VAR_NODE *var, const char *name)
613 {
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;
619 }
620
get_scope_item_type(PHP_SCOPE_TABLE scope,const char * name)621 PHP_SCOPE_ITEM_TYPE get_scope_item_type(PHP_SCOPE_TABLE scope, const char *name)
622 {
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;
628 }
629 return PHP_SCOPE_NONE;
630 }
631
get_scope_item(PHP_SCOPE_TABLE scope,const char * name)632 PHP_SCOPE_ITEM *get_scope_item(PHP_SCOPE_TABLE scope, const char *name)
633 {
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;
640 }
641 return 0;
642 }
643
get_scope_var_name(PHP_SCOPE_TABLE scope,PHP_VAR_NODE * var)644 const char *get_scope_var_name(PHP_SCOPE_TABLE scope, PHP_VAR_NODE *var)
645 {
646 PHP_SCOPE_TABLE_TYPE *scope_map = (PHP_SCOPE_TABLE_TYPE *)scope;
647
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();
653 }
654 }
655 }
656 return 0;
657 }
658
659
660 /* array operations */
array_get_ith_key(PHP_VALUE_NODE * array,int i)661 const std::string &array_get_ith_key(PHP_VALUE_NODE *array, int i)
662 {
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;
667 }
668
669
array_get_by_str_key(PHP_VALUE_NODE * array,const std::string & key)670 PHP_VAR_NODE *array_get_by_str_key(PHP_VALUE_NODE *array, const std::string &key)
671 {
672 if ( array->type != PHP_VAL_ARRAY ) {
673 return 0;
674 }
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;
685 }
686 }
687
array_get_by_int_key(PHP_VALUE_NODE * array,int key)688 PHP_VAR_NODE *array_get_by_int_key(PHP_VALUE_NODE *array, int key)
689 {
690 if ( array->type != PHP_VAL_ARRAY ) {
691 return 0;
692 }
693 char s_key[32];
694 snprintf(s_key, sizeof(s_key), "%d", key);
695 return array_get_by_str_key(array, s_key);
696 }
697
array_get_by_key(PHP_VALUE_NODE * array,PHP_VALUE_NODE * key)698 PHP_VAR_NODE *array_get_by_key(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key)
699 {
700 if ( array->type != PHP_VAL_ARRAY ) {
701 return 0;
702 }
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);
706 }
707
array_set_by_key(PHP_VALUE_NODE * array,PHP_VALUE_NODE * key,PHP_VAR_NODE * node)708 void array_set_by_key(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key, PHP_VAR_NODE *node)
709 {
710 if ( array->type != PHP_VAL_ARRAY ) {
711 return;
712 }
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);
718 }
719
array_add_to_str_key(PHP_VALUE_NODE * array,const std::string & key,PHP_VAR_NODE * node)720 void array_add_to_str_key(PHP_VALUE_NODE *array, const std::string &key, PHP_VAR_NODE *node)
721 {
722 if ( array->type != PHP_VAL_ARRAY ) {
723 return ;
724 }
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);
730 }
731 }
732
array_remove_at_str_key(PHP_VALUE_NODE * array,const std::string & key)733 void array_remove_at_str_key(PHP_VALUE_NODE *array, const std::string &key)
734 {
735 if ( array->type != PHP_VAL_ARRAY ) {
736 return ;
737 }
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;
747 }
748 }
749 }
750 }
751
array_add_to_int_key(PHP_VALUE_NODE * array,int key,PHP_VAR_NODE * node)752 void array_add_to_int_key(PHP_VALUE_NODE *array, int key, PHP_VAR_NODE *node)
753 {
754 char s_key[32];
755 snprintf(s_key, sizeof(s_key), "%d", key);
756 array_add_to_str_key(array, s_key, node);
757 }
758
759
array_is_key_here(PHP_VALUE_NODE * array,PHP_VALUE_NODE * key)760 int array_is_key_here(PHP_VALUE_NODE *array, PHP_VALUE_NODE *key)
761 {
762 if ( array->type != PHP_VAL_ARRAY ) {
763 return 0;
764 }
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);
769
770 return arr_ptr->array.count(arr_key);
771 }
772
array_get_size(PHP_VALUE_NODE * array)773 int array_get_size(PHP_VALUE_NODE *array)
774 {
775 if ( array->type != PHP_VAL_ARRAY ) {
776 return 0;
777 }
778 PHP_ARRAY_TYPE *arr_ptr = (PHP_ARRAY_TYPE *)array->ptr_val;
779
780 return arr_ptr->array.size();
781 }
782
array_push_back(PHP_VALUE_NODE * array)783 PHP_VAR_NODE *array_push_back(PHP_VALUE_NODE *array)
784 {
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;
789 }
790 }
791 // array size reached 64K ?!
792 return 0;
793 }
794
795 /* value manipulation - assignment and disposal */
796
value_value_assign(PHP_VALUE_NODE * dst,PHP_VALUE_NODE * src)797 void value_value_assign(PHP_VALUE_NODE *dst, PHP_VALUE_NODE *src)
798 {
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;
817 }
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);
825 }
826 break;
827 }
828
829 case PHP_VAL_VAR_NODE:
830 case PHP_VAL_INT_DATA: break;
831 }
832 }
833
var_node_free(PHP_VAR_NODE * var)834 void var_node_free(PHP_VAR_NODE *var)
835 {
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;
841 }
842 }
843
value_value_free(PHP_VALUE_NODE * val)844 void value_value_free(PHP_VALUE_NODE *val)
845 {
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;
856 }
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);
862 }
863 delete ((PHP_ARRAY_TYPE *)val->ptr_val);
864 break;
865 }
866 case PHP_VAL_OBJECT: break;
867
868 case PHP_VAL_VAR_NODE:
869 case PHP_VAL_INT_DATA: break;
870 }
871 val->type = PHP_VAL_NONE;
872 }
873
874 /* casting functions */
cast_value_dnum(PHP_VALUE_NODE * val)875 void cast_value_dnum(PHP_VALUE_NODE *val)
876 {
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;
887 }
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;
892 }
893 val->type = PHP_VAL_INT;
894 }
895
cast_value_bool(PHP_VALUE_NODE * val)896 void cast_value_bool(PHP_VALUE_NODE *val)
897 {
898 cast_value_dnum(val);
899 val->type = PHP_VAL_BOOL;
900 }
901
cast_value_fnum(PHP_VALUE_NODE * val)902 void cast_value_fnum(PHP_VALUE_NODE *val)
903 {
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;
914 }
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;
919 }
920 val->type = PHP_VAL_FLOAT;
921 }
922
cast_value_str(PHP_VALUE_NODE * val)923 void cast_value_str(PHP_VALUE_NODE *val)
924 {
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;
935 }
936 case PHP_VAL_OBJECT: strcpy(buff, "Object"); break;
937 case PHP_VAL_VAR_NODE:
938 case PHP_VAL_INT_DATA: assert(0); break;
939 }
940 val->str_val = strdup(buff);
941 val->type = PHP_VAL_STRING;
942 }
943
cast_value_array(PHP_VALUE_NODE * val)944 void cast_value_array(PHP_VALUE_NODE *val)
945 {
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;
956 }
957 val->ptr_val = new PHP_ARRAY_TYPE;
958 val->type = PHP_VAL_ARRAY;
959 }
960
961 /*
962 * Function calls
963 */
make_func_call_exp(char * func_name,PHP_EXP_NODE * args)964 PHP_EXP_NODE *make_func_call_exp(char *func_name, PHP_EXP_NODE *args)
965 {
966 PHP_EXP_NODE *call_node = make_zero_exp_node();
967
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;
976
977 return call_node;
978 }
979
make_func_call_param_list()980 PHP_EXP_NODE *make_func_call_param_list()
981 {
982 PHP_VAR_NODE *params = make_array_var();
983
984 PHP_EXP_NODE *exp_node = make_zero_exp_node();
985
986 exp_node->op = PHP_OP_VAR;
987 exp_node->var_node = params;
988
989 return exp_node;
990 }
991
func_call_add_expr(PHP_VAR_NODE * paramlist,PHP_EXP_NODE * arg,int byref)992 void func_call_add_expr(PHP_VAR_NODE *paramlist, PHP_EXP_NODE *arg, int byref)
993 {
994 PHP_VAR_NODE *node = array_push_back(¶mlist->value);
995 node->value.type = PHP_VAL_INT_DATA;
996 node->value.ptr_val = arg;
997 if ( byref ) {
998 node->flags |= PHP_VARFLAG_BYREF;
999 }
1000 }
1001
php_add_native_func(PHP_BLTIN_FUNC_DEF * def)1002 void php_add_native_func(PHP_BLTIN_FUNC_DEF *def)
1003 {
1004 if ( get_scope_item_type(g_global_scope, def->name) != PHP_SCOPE_NONE ) {
1005 //
1006 // Error: something already defined by this name
1007 //
1008 php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined");
1009 return;
1010 }
1011 PHP_SCOPE_TABLE func_scope = make_scope_table();
1012
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];
1016
1017 //
1018 // Built-in functions don't have class specifier, and can handle
1019 // default arguments internally
1020 //
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);
1026
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;
1031 }
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;
1035
1036 add_func_2_scope(g_global_scope, decl_node);
1037 }
1038
php_add_native_class(const char * name,PHP_NATIVE_PROP_GET_FUNC_PTR prop_get_native_ptr)1039 void php_add_native_class(const char *name, PHP_NATIVE_PROP_GET_FUNC_PTR prop_get_native_ptr)
1040 {
1041 if ( get_scope_item_type(g_global_scope, name) != PHP_SCOPE_NONE ) {
1042 //
1043 // Error: something already defined by this name
1044 //
1045 php_report_error(PHP_ERROR, "Can't add scope item: symbol already defined");
1046 return;
1047 }
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);
1053 }
1054
php_engine_init()1055 void php_engine_init()
1056 {
1057 g_global_scope = make_scope_table();
1058
1059 g_current_scope = g_global_scope;
1060
1061 g_scope_stack = new PHP_SCOPE_STACK_TYPE;
1062
1063 // here built-in functions/objects/vars are loaded
1064 php_init_core_lib();
1065 php_init_amule_lib();
1066 }
1067
php_exp_tree_free(PHP_EXP_NODE * tree)1068 void php_exp_tree_free(PHP_EXP_NODE *tree)
1069 {
1070 if ( !tree ) {
1071 return;
1072 }
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);
1088 }
1089 value_value_free(&args->value);
1090 delete tree->tree_node.right->var_node;
1091 delete tree->tree_node.right;
1092 }
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;
1101 }
1102 }
1103 break;
1104 case PHP_OP_MUX:
1105 php_exp_tree_free(tree->exp_node);
1106 /* fall through */
1107 default:
1108 // all other things using left/right
1109 php_exp_tree_free(tree->tree_node.left);
1110 php_exp_tree_free(tree->tree_node.right);
1111 }
1112
1113 delete tree;
1114 }
1115
php_syn_tree_free(PHP_SYN_NODE * tree)1116 void php_syn_tree_free(PHP_SYN_NODE *tree)
1117 {
1118 while ( tree ) {
1119 switch ( tree->type ) {
1120 case PHP_ST_EXPR:
1121 case PHP_ST_RET:
1122 php_exp_tree_free(tree->node_expr);
1123 break;
1124 case PHP_ST_ECHO: {
1125 PHP_EXP_NODE *curr = tree->node_expr;
1126 while (curr) {
1127 PHP_EXP_NODE *next = curr->next;
1128 php_exp_tree_free(curr->exp_node);
1129 delete curr;
1130 curr = next;
1131 }
1132 }
1133 break;
1134 case PHP_ST_IF:
1135 php_exp_tree_free(tree->node_if.cond);
1136 php_syn_tree_free(tree->node_if.code_if);
1137 php_syn_tree_free(tree->node_if.code_else);
1138 break;
1139 case PHP_ST_WHILE:
1140 case PHP_ST_DO_WHILE:
1141 php_exp_tree_free(tree->node_while.cond);
1142 php_syn_tree_free(tree->node_while.code);
1143 break;
1144 case PHP_ST_FOR:
1145 php_exp_tree_free(tree->node_for.do_start);
1146 php_exp_tree_free(tree->node_for.cond);
1147 php_exp_tree_free(tree->node_for.do_next);
1148 php_syn_tree_free(tree->node_for.code);
1149 break;
1150 case PHP_ST_FOREACH:
1151 php_exp_tree_free(tree->node_foreach.elems);
1152 php_syn_tree_free(tree->node_foreach.code);
1153 break;
1154 case PHP_ST_CONTINUE:
1155 case PHP_ST_BREAK:
1156 break;
1157 case PHP_ST_FUNC_DECL:
1158 if ( !tree->func_decl->is_native ) {
1159 php_syn_tree_free(tree->func_decl->code);
1160 }
1161 delete_scope_table(tree->func_decl->scope);
1162 free(tree->func_decl->name);
1163 for(int i = 0; i < tree->func_decl->param_count; i++) {
1164 if (tree->func_decl->params[i].class_name) {
1165 free(tree->func_decl->params[i].class_name);
1166 }
1167 }
1168 delete [] tree->func_decl->params;
1169 delete tree->func_decl;
1170 break;
1171 case PHP_ST_SWITCH: {
1172 php_exp_tree_free(tree->node_switch.cond);
1173 php_syn_tree_free(tree->node_switch.case_list->exp_node->tree_node.syn_right);
1174 PHP_EXP_NODE *curr = tree->node_switch.case_list;
1175 while (curr) {
1176 PHP_EXP_NODE *next = curr->next;
1177 if ( curr->exp_node ) {
1178 php_exp_tree_free(curr->exp_node->tree_node.left);
1179 delete curr->exp_node;
1180 }
1181 delete curr;
1182 curr = next;
1183 }
1184 }
1185 break;
1186 case PHP_ST_CLASS_DECL:
1187 free(tree->class_decl->name);
1188 delete tree->class_decl;
1189 break;
1190 }
1191 PHP_SYN_NODE *next_node = tree->next_node;
1192 delete tree;
1193 tree = next_node;
1194 }
1195 }
1196
php_engine_free()1197 void php_engine_free()
1198 {
1199 if ( g_global_scope ) {
1200 delete_scope_table(g_global_scope);
1201 }
1202 php_syn_tree_free(g_syn_tree_top);
1203 g_global_scope = 0;
1204 g_current_scope = 0;
1205 delete (PHP_SCOPE_STACK_TYPE *)g_scope_stack;
1206 }
1207
1208 /*
1209 * Create reference. This is recoursive process, since operators []
1210 * can be stacked: $a[1][2][3] = & $b;
1211 * There's 3 valid cases in making reference:
1212 * 1,2. Target is scalar variable or variable by name ${xxx}
1213 * 3. Target is member of array.
1214 */
exp_set_ref(PHP_EXP_NODE * expr,PHP_VAR_NODE * var,PHP_VALUE_NODE * key)1215 static void exp_set_ref(PHP_EXP_NODE *expr, PHP_VAR_NODE *var, PHP_VALUE_NODE *key)
1216 {
1217 switch ( expr->op ) {
1218 case PHP_OP_VAR: {
1219 if ( expr->var_si_node->var != var ) {
1220 if ( key ) {
1221 cast_value_array(&expr->var_si_node->var->value);
1222 array_set_by_key(&expr->var_si_node->var->value, key, var);
1223 } else {
1224 var_node_free(expr->var_si_node->var);
1225 expr->var_si_node->var = var;
1226 var->ref_count++;
1227 }
1228 }
1229 }
1230 break;
1231 case PHP_OP_ARRAY_BY_KEY: {
1232 PHP_VALUE_NODE i_key;
1233 i_key.type = PHP_VAL_NONE;
1234 php_expr_eval(expr->tree_node.right, &i_key);
1235 exp_set_ref(expr->tree_node.left, var, &i_key);
1236 }
1237 break;
1238 default:
1239 php_report_error(PHP_ERROR, "Bad left part of operator =&: (%d)",
1240 expr->tree_node.left->op);
1241 }
1242 }
1243
1244 /*
1245 * This is heart of expression tree: evaluation. It's split into 2 functions
1246 * where 1 evaluates "value" of expression, and other evaluates "lvalue" i.e. assignable
1247 * entity from given subtree.
1248 */
1249
php_expr_eval(PHP_EXP_NODE * expr,PHP_VALUE_NODE * result)1250 void php_expr_eval(PHP_EXP_NODE *expr, PHP_VALUE_NODE *result)
1251 {
1252 PHP_VALUE_NODE result_val_right, result_val_left;
1253 PHP_VAR_NODE *lval_node = 0;
1254 PHP_SCOPE_ITEM *si = 0;
1255 result_val_right.type = PHP_VAL_NONE;
1256 result_val_left.type = PHP_VAL_NONE;
1257 switch(expr->op) {
1258 case PHP_OP_VAL:
1259 if ( result ) {
1260 value_value_assign(result, &expr->val_node);
1261 }
1262 break;
1263 case PHP_OP_VAR:
1264 if ( result ) {
1265 value_value_assign(result, &expr->var_si_node->var->value);
1266 }
1267 break;
1268 case PHP_OP_ASS:
1269 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1270 if ( !lval_node ) {
1271 break;
1272 }
1273 php_expr_eval(expr->tree_node.right, &lval_node->value);
1274 if ( result ) {
1275 value_value_assign(result, &lval_node->value);
1276 }
1277 break;
1278 case PHP_OP_ARRAY_BY_KEY:
1279 php_expr_eval(expr->tree_node.right, &result_val_right);
1280 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1281 cast_value_array(&lval_node->value);
1282 cast_value_str(&result_val_right);
1283 lval_node = array_get_by_key(&lval_node->value, &result_val_right);
1284 if ( result ) {
1285 value_value_assign(result, &lval_node->value);
1286 }
1287 break;
1288 case PHP_MAKE_REF:
1289 lval_node = php_expr_eval_lvalue(expr->tree_node.right);
1290 if ( !lval_node ) {
1291 break;
1292 }
1293 exp_set_ref(expr->tree_node.left, lval_node, 0);
1294 break;
1295 case PHP_OP_ARRAY:
1296 if ( result ) {
1297 PHP_EXP_NODE *curr = expr->tree_node.left;
1298 value_value_free(result);
1299 cast_value_array(result);
1300 while ( curr ) {
1301 switch( curr->exp_node->op ) {
1302 case PHP_OP_ARRAY_PAIR:
1303 if ( curr->exp_node->tree_node.right ) {
1304 php_expr_eval(curr->exp_node->tree_node.left, &result_val_left);
1305 cast_value_str(&result_val_left);
1306 lval_node = array_get_by_key(result, &result_val_left);
1307 value_value_free(&result_val_left);
1308 php_expr_eval(curr->exp_node->tree_node.right, &lval_node->value);
1309 } else {
1310 lval_node = array_push_back(result);
1311 php_expr_eval(curr->exp_node->tree_node.left, &lval_node->value);
1312 }
1313 break;
1314 case PHP_OP_ARRAY_REF_PAIR:
1315 lval_node = php_expr_eval_lvalue(curr->exp_node->tree_node.right);
1316 break;
1317 default:
1318 php_report_error(PHP_INTERNAL_ERROR, "Array list contain wrong node");
1319 return;
1320 }
1321 curr = curr->next;
1322 }
1323 }
1324 break;
1325 case PHP_OP_FUNC_CALL:
1326 php_run_func_call(expr, result);
1327 break;
1328 case PHP_OP_LIST: {
1329 PHP_EXP_NODE *curr = expr;
1330 while ( curr ) {
1331 if ( curr->exp_node ) {
1332 php_expr_eval(curr->exp_node, result);
1333 }
1334 curr = curr->next;
1335 }
1336 }
1337 break;
1338 case PHP_OP_CAT:
1339 php_expr_eval(expr->tree_node.right, &result_val_right);
1340 php_expr_eval(expr->tree_node.left, &result_val_left);
1341 if ( result ) {
1342 cast_value_str(&result_val_left);
1343 cast_value_str(&result_val_right);
1344 value_value_free(result);
1345 result->type = PHP_VAL_STRING;
1346 // using "malloc" and not "new" since all strings are freed
1347 // later with "free" and not "delete"
1348 result->str_val = (char *)malloc(strlen(result_val_left.str_val) +
1349 strlen(result_val_right.str_val) + 1);
1350 strcpy(result->str_val, result_val_left.str_val);
1351 strcat(result->str_val, result_val_right.str_val);
1352 }
1353 break;
1354 case PHP_OP_MUX:
1355 php_expr_eval(expr->exp_node, &result_val_right);
1356 cast_value_bool(&result_val_right);
1357 if ( result_val_right.int_val ) {
1358 php_expr_eval(expr->tree_node.left, result);
1359 } else {
1360 php_expr_eval(expr->tree_node.right, result);
1361 }
1362 break;
1363 case PHP_OP_CAST_INT:
1364 if ( result ) {
1365 php_expr_eval(expr->tree_node.left, result);
1366 cast_value_dnum(result);
1367 }
1368 break;
1369 case PHP_OP_CAST_FLOAT:
1370 if ( result ) {
1371 php_expr_eval(expr->tree_node.left, result);
1372 cast_value_fnum(result);
1373 }
1374 break;
1375 case PHP_OP_CAST_BOOL:
1376 if ( result ) {
1377 php_expr_eval(expr->tree_node.left, result);
1378 cast_value_bool(result);
1379 }
1380 break;
1381 case PHP_OP_CAST_STR:
1382 if ( result ) {
1383 php_expr_eval(expr->tree_node.left, result);
1384 cast_value_str(result);
1385 }
1386 break;
1387 case PHP_OP_LOG_NOT:
1388 if ( result ) {
1389 php_expr_eval(expr->tree_node.left, &result_val_right);
1390 cast_value_bool(&result_val_right);
1391 result_val_right.int_val = !result_val_right.int_val;
1392 value_value_assign(result, &result_val_right);
1393 }
1394 break;
1395 case PHP_OP_NOT:
1396 if ( result ) {
1397 php_expr_eval(expr->tree_node.left, &result_val_right);
1398 cast_value_bool(&result_val_right);
1399 result_val_right.int_val = ~result_val_right.int_val;
1400 value_value_assign(result, &result_val_right);
1401 }
1402 break;
1403 case PHP_OP_ADD:
1404 case PHP_OP_SUB:
1405 case PHP_OP_MUL:
1406 case PHP_OP_DIV:
1407 php_expr_eval(expr->tree_node.right, &result_val_right);
1408 php_expr_eval(expr->tree_node.left, &result_val_left);
1409 if ( result ) {
1410 php_eval_simple_math(expr->op, &result_val_left, &result_val_right, result);
1411 }
1412 break;
1413 case PHP_OP_SHL:
1414 case PHP_OP_SHR:
1415 case PHP_OP_OR:
1416 case PHP_OP_AND:
1417 case PHP_OP_XOR:
1418 case PHP_OP_LOG_OR:
1419 case PHP_OP_LOG_AND:
1420 case PHP_OP_LOG_XOR:
1421 php_expr_eval(expr->tree_node.right, &result_val_right);
1422 php_expr_eval(expr->tree_node.left, &result_val_left);
1423 if ( result ) {
1424 php_eval_int_math(expr->op, &result_val_left, &result_val_right, result);
1425 }
1426 break;
1427 case PHP_OP_EQ:
1428 case PHP_OP_NEQ:
1429 case PHP_OP_GRT:
1430 case PHP_OP_LWR:
1431 php_expr_eval(expr->tree_node.right, &result_val_right);
1432 php_expr_eval(expr->tree_node.left, &result_val_left);
1433 if ( result ) {
1434 php_eval_compare(expr->op, &result_val_left, &result_val_right, result);
1435 }
1436 break;
1437 case PHP_OP_PRINT:
1438 php_expr_eval(expr->tree_node.left, &result_val_right);
1439 cast_value_str(&result_val_right);
1440 //
1441 // I print to buffer
1442 CPhPLibContext::Print(result_val_right.str_val);
1443 break;
1444 case PHP_OP_OBJECT_DEREF: // $x->y
1445 // take variable from scope of current object
1446 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1447 if ( !lval_node ) {
1448 php_report_error(PHP_ERROR, "Left part of -> must be lvalue");
1449 return;
1450 }
1451 if ( lval_node->value.type != PHP_VAL_OBJECT ) {
1452 php_report_error(PHP_ERROR, "Left part of -> must be an object");
1453 return;
1454 }
1455 if ( get_scope_item_type(g_global_scope, lval_node->value.obj_val.class_name) == PHP_SCOPE_NONE ) {
1456 php_report_error(PHP_ERROR, "Undeclared object");
1457 return;
1458 }
1459 si = get_scope_item(g_global_scope, lval_node->value.obj_val.class_name);
1460 if ( si->type != PHP_SCOPE_CLASS ) {
1461 php_report_error(PHP_INTERNAL_ERROR, "Object classname is not name of class");
1462 return;
1463 }
1464 // left part is ok, let's check the right
1465 if ( (expr->tree_node.right->op != PHP_OP_VAL) || (expr->tree_node.right->val_node.type != PHP_VAL_STRING) ) {
1466 php_report_error(PHP_ERROR, "Right part of -> must be string value");
1467 return;
1468 }
1469 if ( si->class_decl->class_decl->is_native ) {
1470 si->class_decl->class_decl->native_prop_get_ptr(lval_node->value.obj_val.inst_ptr,
1471 expr->tree_node.right->val_node.str_val, result);
1472 } else {
1473 php_report_error(PHP_ERROR, "Only native classes supported");
1474 return;
1475 }
1476 break;
1477 case PHP_OP_CLASS_DEREF: // A::y
1478 // take variable (static) from scope of current class
1479 php_report_error(PHP_ERROR, "Value of static class members not supported");
1480 break;
1481 default: ;
1482
1483 }
1484 value_value_free(&result_val_left);
1485 value_value_free(&result_val_right);
1486 }
1487
php_expr_eval_lvalue(PHP_EXP_NODE * expr)1488 PHP_VAR_NODE *php_expr_eval_lvalue(PHP_EXP_NODE *expr)
1489 {
1490 PHP_VAR_NODE *lval_node = 0;
1491
1492 PHP_VALUE_NODE index;
1493 index.type = PHP_VAL_NONE;
1494
1495 switch(expr->op) {
1496 case PHP_OP_VAR:
1497 lval_node = expr->var_si_node->var;
1498 break;
1499 case PHP_OP_ARRAY_BY_KEY:
1500 lval_node = php_expr_eval_lvalue(expr->tree_node.left);
1501 if ( !lval_node ) {
1502 break;
1503 }
1504
1505 cast_value_array(&lval_node->value);
1506 if ( expr->tree_node.right ) {
1507 php_expr_eval(expr->tree_node.right, &index);
1508 if ( index.type == PHP_VAL_NONE ) {
1509 // something got wrong: evaluation result is not a value
1510 return 0;
1511 }
1512 cast_value_str(&index);
1513 lval_node = array_get_by_key(&lval_node->value, &index);
1514 value_value_free(&index);
1515 } else {
1516 // this is "$xxx[] = " construct.
1517 lval_node = array_push_back(&lval_node->value);
1518 }
1519 case PHP_OP_VAR_BY_EXP: // ${"xxx"}
1520 // should take variable from current scope
1521 break;
1522 case PHP_OP_OBJECT_DEREF: // $x->y
1523 // take variable from scope of current object
1524 php_report_error(PHP_ERROR, "Assign to class members not supported");
1525 break;
1526 case PHP_OP_CLASS_DEREF: // A::y
1527 // take variable (static) from scope of current class
1528 php_report_error(PHP_ERROR, "Assign to static class members not supported");
1529 break;
1530 default:
1531 //
1532 // Error: expression can not be taken as lvalue
1533 //
1534 php_report_error(PHP_ERROR, "This expression can't be used as lvalue");
1535 }
1536 return lval_node;
1537 }
1538
cast_type_resolve(PHP_VALUE_NODE * op1,PHP_VALUE_NODE * op2)1539 static PHP_VALUE_TYPE cast_type_resolve(PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2)
1540 {
1541 if ( (op1->type == PHP_VAL_FLOAT) || (op2->type == PHP_VAL_FLOAT) ) {
1542 cast_value_fnum(op1);
1543 cast_value_fnum(op2);
1544 return PHP_VAL_FLOAT;
1545 } else {
1546 cast_value_dnum(op1);
1547 cast_value_dnum(op2);
1548 return PHP_VAL_INT;
1549 }
1550 }
1551
1552 /*
1553 * Same as simple_math, but result is always bool
1554 */
php_eval_compare(PHP_EXP_OP op,PHP_VALUE_NODE * op1,PHP_VALUE_NODE * op2,PHP_VALUE_NODE * result)1555 void php_eval_compare(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1556 {
1557 result->type = PHP_VAL_BOOL;
1558 if ( (op1->type == PHP_VAL_STRING) || (op2->type == PHP_VAL_STRING) ) {
1559 cast_value_str(op1);
1560 cast_value_str(op2);
1561 int cmp_val = strcmp(op1->str_val, op2->str_val);
1562 switch(op) {
1563 case PHP_OP_EQ:
1564 result->int_val = (cmp_val == 0);
1565 break;
1566 case PHP_OP_NEQ:
1567 result->int_val = (cmp_val != 0);
1568 break;
1569 case PHP_OP_GRT:
1570 result->int_val = (cmp_val > 0);
1571 break;
1572 case PHP_OP_LWR:
1573 result->int_val = (cmp_val < 0);
1574 break;
1575 case PHP_OP_GRT_EQ:
1576 result->int_val = (cmp_val >= 0);
1577 break;
1578 case PHP_OP_LWR_EQ:
1579 result->int_val = (cmp_val <= 0);
1580 break;
1581 default:
1582 php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op");
1583 }
1584 } else {
1585 PHP_VALUE_TYPE restype = cast_type_resolve(op1, op2);
1586 switch(op) {
1587 case PHP_OP_EQ:
1588 if ( restype == PHP_VAL_FLOAT ) {
1589 result->int_val = op1->float_val == op2->float_val;
1590 } else {
1591 result->int_val = op1->int_val == op2->int_val;
1592 }
1593 break;
1594 case PHP_OP_NEQ:
1595 if ( restype == PHP_VAL_FLOAT ) {
1596 result->int_val = op1->float_val != op2->float_val;
1597 } else {
1598 result->int_val = op1->int_val != op2->int_val;
1599 }
1600 break;
1601 case PHP_OP_GRT:
1602 if ( restype == PHP_VAL_FLOAT ) {
1603 result->int_val = op1->float_val > op2->float_val;
1604 } else {
1605 result->int_val = op1->int_val > op2->int_val;
1606 }
1607 break;
1608 case PHP_OP_GRT_EQ:
1609 if ( restype == PHP_VAL_FLOAT ) {
1610 result->int_val = op1->float_val >= op2->float_val;
1611 } else {
1612 result->int_val = op1->int_val >= op2->int_val;
1613 }
1614 break;
1615 case PHP_OP_LWR:
1616 if ( restype == PHP_VAL_FLOAT ) {
1617 result->int_val = op1->float_val < op2->float_val;
1618 } else {
1619 result->int_val = op1->int_val < op2->int_val;
1620 }
1621 break;
1622 case PHP_OP_LWR_EQ:
1623 if ( restype == PHP_VAL_FLOAT ) {
1624 result->int_val = op1->float_val <= op2->float_val;
1625 } else {
1626 result->int_val = op1->int_val <= op2->int_val;
1627 }
1628 break;
1629 default:
1630 php_report_error(PHP_INTERNAL_ERROR, "This op is not compare op");
1631 }
1632 }
1633 }
1634
php_eval_simple_math(PHP_EXP_OP op,PHP_VALUE_NODE * op1,PHP_VALUE_NODE * op2,PHP_VALUE_NODE * result)1635 void php_eval_simple_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1636 {
1637 result->type = cast_type_resolve(op1, op2);
1638 switch(op) {
1639 case PHP_OP_ADD:
1640 if ( result->type == PHP_VAL_FLOAT ) {
1641 result->float_val = op1->float_val + op2->float_val;
1642 } else {
1643 result->int_val = op1->int_val + op2->int_val;
1644 }
1645 break;
1646 case PHP_OP_SUB:
1647 if ( result->type == PHP_VAL_FLOAT ) {
1648 result->float_val = op1->float_val - op2->float_val;
1649 } else {
1650 result->int_val = op1->int_val - op2->int_val;
1651 }
1652 break;
1653 case PHP_OP_MUL:
1654 if ( result->type == PHP_VAL_FLOAT ) {
1655 result->float_val = op1->float_val * op2->float_val;
1656 } else {
1657 result->int_val = op1->int_val * op2->int_val;
1658 }
1659 break;
1660 case PHP_OP_DIV:
1661 if ( result->type == PHP_VAL_FLOAT ) {
1662 result->float_val = op1->float_val / op2->float_val;
1663 } else {
1664 result->int_val = op1->int_val / op2->int_val;
1665 }
1666 break;
1667 default:
1668 php_report_error(PHP_INTERNAL_ERROR, "This op is not simple math");
1669 }
1670 }
1671
php_eval_int_math(PHP_EXP_OP op,PHP_VALUE_NODE * op1,PHP_VALUE_NODE * op2,PHP_VALUE_NODE * result)1672 void php_eval_int_math(PHP_EXP_OP op, PHP_VALUE_NODE *op1, PHP_VALUE_NODE *op2, PHP_VALUE_NODE *result)
1673 {
1674 cast_value_dnum(op1);
1675 cast_value_dnum(op2);
1676 result->type = PHP_VAL_INT;
1677 switch(op) {
1678 case PHP_OP_SHL:
1679 result->int_val = op1->int_val << op2->int_val;
1680 break;
1681 case PHP_OP_SHR:
1682 result->int_val = op1->int_val >> op2->int_val;
1683 break;
1684 case PHP_OP_OR:
1685 result->int_val = op1->int_val | op2->int_val;
1686 break;
1687 case PHP_OP_LOG_OR:
1688 result->int_val = op1->int_val || op2->int_val;
1689 break;
1690 case PHP_OP_AND:
1691 result->int_val = op1->int_val & op2->int_val;
1692 break;
1693 case PHP_OP_LOG_AND:
1694 result->int_val = op1->int_val && op2->int_val;
1695 break;
1696 case PHP_OP_LOG_XOR:
1697 op1->int_val = op1->int_val ? 1 : 0;
1698 op2->int_val = op2->int_val ? 1 : 0;
1699 /* fall through */
1700 case PHP_OP_XOR:
1701 result->int_val = op1->int_val ^ op2->int_val;
1702 break;
1703 default:
1704 php_report_error(PHP_INTERNAL_ERROR, "This op is not int math");
1705 }
1706 }
1707
1708 //
1709 // left = VAR(func_name), right=ARRAY(args)
php_run_func_call(PHP_EXP_NODE * node,PHP_VALUE_NODE * result)1710 void php_run_func_call(PHP_EXP_NODE *node, PHP_VALUE_NODE *result)
1711 {
1712 PHP_EXP_NODE *l_node = node->tree_node.left;
1713 PHP_EXP_NODE *r_node = node->tree_node.right;
1714 if ( (l_node->op != PHP_OP_VAL) || (l_node->val_node.type != PHP_VAL_STRING) ||
1715 (r_node->op != PHP_OP_VAR) || (r_node->var_node->value.type != PHP_VAL_ARRAY) ) {
1716 //
1717 // Internal error: function name must be string value node, and
1718 // params must be an array
1719 //
1720 php_report_error(PHP_INTERNAL_ERROR, "Function call node have wrong data");
1721 return ;
1722 }
1723 PHP_SCOPE_ITEM *si = get_scope_item(g_global_scope, l_node->val_node.str_val);
1724 if ( !si ) {
1725 //
1726 // Error: undeclared symbol
1727 //
1728 php_report_error(PHP_ERROR, "Function [ %s ] is not defined", l_node->val_node.str_val);
1729 return;
1730 }
1731 if ( si->type != PHP_SCOPE_FUNC) {
1732 //
1733 // Error: defined, but wrong type !
1734 //
1735 php_report_error(PHP_ERROR, "Item [ %s ] is not a function", l_node->val_node.str_val);
1736 return;
1737 }
1738 PHP_SYN_NODE *func = si->func;
1739 if ( func->type != PHP_ST_FUNC_DECL ) {
1740 //
1741 // Internal error: node not a function
1742 //
1743 php_report_error(PHP_INTERNAL_ERROR, "Wrong type in function decl node");
1744 return;
1745 }
1746
1747 //
1748 // Switch stack and call function
1749 //
1750
1751 PHP_SYN_FUNC_DECL_NODE *func_decl = func->func_decl;
1752
1753 std::map<std::string, PHP_VAR_NODE *> saved_vars;
1754 func_scope_init(func_decl->params, func_decl->param_count,
1755 (PHP_SCOPE_TABLE_TYPE *)func_decl->scope,
1756 &r_node->var_node->value, saved_vars);
1757
1758 switch_push_scope_table((PHP_SCOPE_TABLE_TYPE *)func_decl->scope);
1759
1760 if ( func_decl->is_native ) {
1761 func_decl->native_ptr(result);
1762 } else {
1763 php_execute(func_decl->code, result);
1764 }
1765
1766 //
1767 // restore stack, free arg list
1768 //
1769 switch_pop_scope_table(0);
1770 func_scope_copy_back(func_decl->params, func_decl->param_count,
1771 (PHP_SCOPE_TABLE_TYPE *)func_decl->scope, &r_node->var_node->value, saved_vars);
1772
1773 //scope_reset_nonstatics(func_decl->scope);
1774
1775 }
1776
1777 /*
1778 * Theoretically speaking this function must run on generated code. On the
1779 * practical side - I need it to debug syntax tree generation. Later, it can
1780 * be changes to generate code for some kind of bytecode for stack machine
1781 */
php_execute(PHP_SYN_NODE * node,PHP_VALUE_NODE * result)1782 int php_execute(PHP_SYN_NODE *node, PHP_VALUE_NODE *result)
1783 {
1784 if ( !node ) {
1785 return 0;
1786 }
1787 while ( node ) {
1788 int curr_exec_result = 0;
1789 PHP_VALUE_NODE cond_result;
1790 cond_result.type = PHP_VAL_NONE;
1791 switch (node->type) {
1792 case PHP_ST_EXPR:
1793 php_expr_eval(node->node_expr, 0);
1794 break;
1795 case PHP_ST_IF:
1796 php_expr_eval(node->node_if.cond, &cond_result);
1797 cast_value_bool(&cond_result);
1798 if ( cond_result.int_val ) {
1799 if ( node->node_if.code_if ) {
1800 curr_exec_result = php_execute(node->node_if.code_if, result);
1801 }
1802 } else {
1803 if ( node->node_if.code_else ) {
1804 curr_exec_result = php_execute(node->node_if.code_else, result);
1805 }
1806 }
1807 break;
1808 case PHP_ST_RET:
1809 if ( node->node_expr ) {
1810 php_expr_eval(node->node_expr, result);
1811 }
1812 if ( node->next_node ) {
1813 //
1814 // Warning: code after "return" statement
1815 //
1816 php_report_error(PHP_WARNING, "code after 'return'");
1817 }
1818 // "return" is ultimate "break"
1819 curr_exec_result = -0xffff;
1820 break;
1821 case PHP_ST_ECHO: {
1822 PHP_EXP_NODE *curr = node->node_expr;
1823 while (curr) {
1824 php_expr_eval(curr->exp_node, &cond_result);
1825 cast_value_str(&cond_result);
1826 CPhPLibContext::Print(cond_result.str_val);
1827 value_value_free(&cond_result);
1828 curr = curr->next;
1829 }
1830 }
1831 break;
1832 case PHP_ST_CONTINUE:
1833 case PHP_ST_BREAK:
1834 if ( node->node_expr ) {
1835 // 'break' or 'continue' used with an argument
1836 php_expr_eval(node->node_expr, &cond_result);
1837 } else {
1838 // without an argument break or continue just 1 loop
1839 cond_result.type = PHP_VAL_INT;
1840 cond_result.int_val = 1;
1841 }
1842 cast_value_dnum(&cond_result);
1843 if ( node->type == PHP_ST_BREAK ) {
1844 curr_exec_result = -(int)(cond_result.int_val);
1845 } else {
1846 curr_exec_result = cond_result.int_val;
1847 }
1848 break;
1849
1850 case PHP_ST_WHILE:
1851 case PHP_ST_DO_WHILE:
1852 if ( node->type == PHP_ST_WHILE ) {
1853 php_expr_eval(node->node_while.cond, &cond_result);
1854 cast_value_bool(&cond_result);
1855 } else {
1856 cond_result.int_val = 1;
1857 }
1858 while ( cond_result.int_val ) {
1859 // evaluate code within while loop
1860 curr_exec_result = php_execute(node->node_while.code, 0);
1861 // if 'break' was used
1862 if ( curr_exec_result < 0 ) {
1863 // decrease number of loops to break
1864 curr_exec_result++;
1865 // and break current loop
1866 break;
1867 }
1868 // normal execution of loop or continue
1869 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1870 curr_exec_result = 0;
1871 // evaluate 'while' loop conditions
1872 php_expr_eval(node->node_while.cond, &cond_result);
1873 cast_value_bool(&cond_result);
1874 }
1875 // if 'continue' was used with an argument > 1
1876 if ( curr_exec_result > 1 ) {
1877 // decrease number of loops to skip
1878 curr_exec_result--;
1879 // and break current loop
1880 break;
1881 }
1882 }
1883 break;
1884 case PHP_ST_FOR:
1885 php_expr_eval(node->node_for.do_start, &cond_result);
1886 php_expr_eval(node->node_for.cond, &cond_result);
1887 cast_value_bool(&cond_result);
1888 while ( cond_result.int_val ) {
1889 curr_exec_result = php_execute(node->node_for.code, 0);
1890 // handle 'break' and 'continue'
1891 if ( curr_exec_result < 0 ) {
1892 curr_exec_result++;
1893 break;
1894 }
1895 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1896 curr_exec_result = 0;
1897 // evaluate 'for' loop conditions
1898 php_expr_eval(node->node_for.do_next, &cond_result);
1899 php_expr_eval(node->node_for.cond, &cond_result);
1900 cast_value_bool(&cond_result);
1901 }
1902 if ( curr_exec_result > 1 ) {
1903 curr_exec_result--;
1904 break;
1905 }
1906 }
1907 break;
1908 case PHP_ST_FOREACH: {
1909 PHP_VAR_NODE *elems = php_expr_eval_lvalue(node->node_foreach.elems);
1910 if ( !elems || (elems->value.type != PHP_VAL_ARRAY) ) {
1911 php_report_error(PHP_ERROR, "Argument of 'foreach' must be array");
1912 break;
1913 }
1914 PHP_ARRAY_TYPE *array = (PHP_ARRAY_TYPE *)elems->value.ptr_val;
1915 PHP_SCOPE_ITEM *i_key = node->node_foreach.i_key;
1916 // keys in array are string values.
1917 if ( i_key ) {
1918 i_key->var->value.type = PHP_VAL_STRING;
1919 }
1920 PHP_SCOPE_ITEM *i_val = node->node_foreach.i_val;
1921 array->current = array->sorted_keys.begin();
1922 while ( array->current != array->sorted_keys.end() ) {
1923 if ( i_key ) {
1924 PHP_VALUE_NODE tmp_val;
1925 tmp_val.type = PHP_VAL_STRING;
1926 tmp_val.str_val = (char *)array->current->c_str();
1927 value_value_assign(&i_key->var->value, &tmp_val);
1928 }
1929 PHP_VALUE_NODE *curr_value = &array->array[*array->current]->value;
1930 value_value_assign(&i_val->var->value, curr_value);
1931 curr_exec_result = php_execute(node->node_foreach.code, 0);
1932 // clean up
1933 if ( i_key ) {
1934 value_value_free(&i_key->var->value);
1935 }
1936 if ( node->node_foreach.byref ) {
1937 value_value_assign(curr_value, &i_val->var->value);
1938 }
1939 value_value_free(&i_val->var->value);
1940 // handle 'break' and 'continue'
1941 if ( curr_exec_result < 0 ) {
1942 curr_exec_result++;
1943 break;
1944 }
1945 if ( curr_exec_result == 0 || curr_exec_result == 1 ) {
1946 curr_exec_result = 0;
1947 // next element
1948 array->current++;
1949 }
1950 if ( curr_exec_result > 1 ) {
1951 curr_exec_result--;
1952 break;
1953 }
1954 }
1955 }
1956 break;
1957 case PHP_ST_SWITCH: {
1958 PHP_SYN_NODE *cur_exec = 0;
1959 // evaluate switch argument
1960 php_expr_eval(node->node_switch.cond, &cond_result);
1961 // loop through list of case statements
1962 PHP_EXP_NODE *curr = node->node_switch.case_list;
1963 while (curr) {
1964 PHP_VALUE_NODE cur_value, cmp_result;
1965 cur_value.type = cmp_result.type = PHP_VAL_NONE;
1966 // TODO make amuleweb not crash when 'default' is used
1967 php_expr_eval(curr->exp_node->tree_node.left, &cur_value);
1968
1969 // switch argument equal to case argument?
1970 php_eval_compare(PHP_OP_EQ, &cur_value, &cond_result, &cmp_result);
1971 if ( cmp_result.int_val ) {
1972 // execute code and rest of case statements
1973 cur_exec = static_cast<PHP_SYN_NODE *>(curr->exp_node->tree_node.syn_right);
1974 break;
1975 }
1976 curr = curr->next;
1977 }
1978 if ( cur_exec ) {
1979 curr_exec_result = php_execute(cur_exec, result);
1980 // break
1981 if (curr_exec_result < 0) curr_exec_result++;
1982 // continue
1983 if (curr_exec_result > 0) curr_exec_result--;
1984 }
1985 }
1986 break;
1987 default: ;
1988 }
1989 if ( curr_exec_result ) {
1990 return curr_exec_result;
1991 }
1992 node = node->next_node;
1993 }
1994 // everything ok, keep going
1995 return 0;
1996 }
1997
1998
1999 //
2000 // call it when something gone wrong
2001 //
php_report_error(PHP_MSG_TYPE err_type,const char * msg,...)2002 void php_report_error(PHP_MSG_TYPE err_type, const char *msg, ...)
2003 {
2004 //
2005 // hope my error message will never be that big.
2006 //
2007 // security is ok, since _user_ errors are not reporting thru
2008 // this function, but handled by scipt itself.
2009 // However, badly written script MAY force user-supplied data to
2010 // leak here and create stack overrun exploit. Be warned.
2011 //
2012 char msgbuf[1024];
2013 const char *type_msg = 0;
2014 switch(err_type) {
2015 case PHP_MESAGE:
2016 type_msg = "PHP:";
2017 break;
2018 case PHP_WARNING:
2019 type_msg = "PHP Warning:";
2020 break;
2021 case PHP_ERROR:
2022 type_msg = "PHP Error:";
2023 break;
2024 case PHP_INTERNAL_ERROR:
2025 type_msg = "PHP Internal Error:";
2026 break;
2027 }
2028
2029 va_list args;
2030 va_start(args, msg);
2031 vsnprintf(msgbuf, sizeof(msgbuf), msg, args);
2032 va_end(args);
2033
2034 printf("%s %s\n", type_msg, msgbuf);
2035 assert(err_type != PHP_INTERNAL_ERROR);
2036 }
2037
2038
phperror(char * s)2039 int phperror(char *s)
2040 {
2041 printf("ERROR in grammar %s after [%s] near line %d\n", s, phptext, phplineno);
2042 return 0;
2043 }
2044
2045 // File_checked_for_headers
2046