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(&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;
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