1 %{
2 //
3 // This file is part of the aMule Project.
4 //
5 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (c) 2005-2011 Froenchenko Leonid ( lfroen@gmail.com / http://www.amule.org )
7 //
8 // Any parts of this program derived from the xMule, lMule or eMule project,
9 // or contributed by third-party developers are copyrighted by their
10 // respective authors.
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
25 //
26 
27 #include <stdio.h>
28 #include <string.h>
29 
30 #include "php_syntree.h"
31 
32 int phplex(void);
33 
34 // add item to syntree list
add_statement_2_list(PHP_SYN_NODE * list,PHP_SYN_NODE * st)35 PHP_SYN_NODE *add_statement_2_list(PHP_SYN_NODE *list, PHP_SYN_NODE *st)
36 {
37 	if ( st && list) {
38 		PHP_SYN_NODE *last = list;
39 		while ( last->next_node ) {
40 			last = last->next_node;
41 		}
42 		last->next_node = st;
43 		return list;
44 	} else if ( st ) {
45 		return st;
46 	} else {
47 		return list;
48 	}
49 }
50 
add_branch_2_elseif(PHP_SYN_NODE * list,PHP_SYN_NODE * branch)51 PHP_SYN_NODE *add_branch_2_elseif(PHP_SYN_NODE *list, PHP_SYN_NODE *branch)
52 {
53 	if ( list ) {
54 		PHP_SYN_NODE *curr_if = list;
55 		while ( curr_if->node_if.code_else ) {
56 			curr_if = curr_if->node_if.code_else;
57 		}
58 		curr_if->node_if.code_else = branch;
59 		return list;
60 	} else {
61 		return branch;
62 	}
63 }
64 
65 %}
66 
67 %union {
68 	PHP_SYN_NODE *syn_node;
69 	PHP_EXP_NODE *exp_node;
70 
71 	char str_val[256];
72 }
73 
74 %type <syn_node> program_tree statement top_statement function_decl_statement top_statement_list
75 %type <syn_node> global_var_list static_var_list
76 %type <syn_node> while_statement foreach_statement for_statement elseif_list else_statement
77 
78 %type <exp_node> VARIABLE variable deref_variable global_var static_var
79 %type <exp_node> parameter_list array_pair_list array_elem
80 %type <exp_node> switch_case_list case_list case_list_item
81 
82 %type <exp_node> expr expr_list for_expr exit_expr const_value function_call func_param_list assignment_list assignment_list_element
83 %type <exp_node> FNUMBER DNUMBER STRING
84 
85 %type <str_val> IDENT optional_class_type
86 
87 /*
88 	All my tokens
89 */
90 %token FNUMBER DNUMBER STRING IDENT VARIABLE
91 
92 %token T_ECHO
93 %token EXIT
94 
95 %token IF DO WHILE ENDWHILE FOR ENDFOR FOREACH ENDFOREACH
96 
97 %token DECLARE ENDDECLARE AS CONST GLOBAL UNSET ISSET EMPTY
98 
99 %token SWITCH ENDSWITCH CASE DEFAULT BREAK CONTINUE
100 %token FUNCTION RETURN
101 %token CLASS INTERFACE EXTENDS IMPLEMENTS OBJECT_OPERATOR
102 %token HASH_ASSIGN LIST ARRAY
103 
104 %token CLASS_SCOPE
105 
106 /*
107 	Things with precedence
108 */
109 %left ','
110 %right PRINT
111 %left '=' PLUS_EQ MINUS_EQ MUL_EQ DIV_EQ CONCAT_EQ MOD_EQ AND_EQ OR_EQ XOR_EQ SL_EQ SR_EQ
112 %left '?' ':'
113 %left LOG_OR
114 %left LOG_XOR
115 %left LOG_AND
116 %left BOOLEAN_OR
117 %left BOOLEAN_AND
118 %left '|'
119 %left '^'
120 %left '&'
121 %nonassoc IS_EQ IS_NOEQUAL IS_IDENTICAL IS_NOIDENTICAL
122 %nonassoc '<' IS_SMALLER_OR_EQ '>' IS_GREATER_OR_EQ
123 %left SL SR
124 %left '+' '-' '.'
125 %left '*' '/' '%'
126 %right '!'
127 %nonassoc INSTANCEOF
128 %right '~' INC DEC INT_CAST DOUBLE_CAST STRING_CAST ARRAY_CAST OBJECT_CAST BOOL_CAST UNSET_CAST '@'
129 %right '['
130 %nonassoc NEW CLONE
131 
132 %left ELSEIF
133 %left ELSE
134 %left ENDIF
135 
136 %right STATIC ABSTRACT FINAL PRIVATE PROTECTED PUBLIC
137 
138 %token START_SCRIPT END_SCRIPT
139 
140 %% /* Rules */
141 
142 program_tree: START_SCRIPT top_statement_list END_SCRIPT { g_syn_tree_top = $2; }
143 ;
144 
145 top_statement_list:
146 		top_statement_list  top_statement { $$ = add_statement_2_list($1, $2); }
147 	|	/* empty */ { $$ = 0; }
148 ;
149 
150 
151 top_statement:
152 		statement
153 	|	START_SCRIPT top_statement_list END_SCRIPT { $$ = $2; }
154 	|	function_decl_statement
155 /*	|	class_decl_statement */
156 ;
157 
158 statement:
159 		'{' top_statement_list '}'							{ $$ = $2; }
160 	|	expr ';'											{ $$ = make_expr_syn_node(PHP_ST_EXPR, $1); }
161 	|	GLOBAL global_var_list ';'							{ $$ = 0; }
162 	|	STATIC static_var_list ';'							{ $$ = $2; }
163 	|	IF '(' expr ')' statement elseif_list else_statement	{ $$ = make_ifelse_syn_node($3, $5, $6, $7); }
164 	|	WHILE '(' expr  ')' while_statement					{ $$ = make_while_loop_syn_node($3, $5, 1); }
165 	|	DO statement WHILE '(' expr ')' ';'					{ $$ = make_while_loop_syn_node($5, $2, 0); }
166 	|	FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement { $$ = make_for_syn_node($3, $5, $7, $9); }
167 	|	SWITCH '(' expr ')' switch_case_list				{ $$ = make_switch_syn_node($3, $5); }
168 	|	CONTINUE ';'										{ $$ = make_expr_syn_node(PHP_ST_CONTINUE, 0); }
169 	|	CONTINUE expr ';'									{ $$ = make_expr_syn_node(PHP_ST_CONTINUE, $2); }
170 	|	BREAK ';'											{ $$ = make_expr_syn_node(PHP_ST_BREAK, 0); }
171 	|	BREAK expr ';'										{ $$ = make_expr_syn_node(PHP_ST_BREAK, $2); }
172 	|	RETURN ';'											{ $$ = make_expr_syn_node(PHP_ST_RET, 0); }
173 	|	RETURN expr ';'										{ $$ = make_expr_syn_node(PHP_ST_RET, $2); }
174 	|	T_ECHO expr_list ';'								{ $$ = make_expr_syn_node(PHP_ST_ECHO, $2); }
175 	|	UNSET '(' variable_list ')' ';'						{  }
176 	|	FOREACH '(' expr AS variable ')' foreach_statement	{
177 				$$ = make_foreach_loop_syn_node($3, 0, $5, $7, 0);
178 			}
179 	|	FOREACH '(' expr AS variable HASH_ASSIGN variable ')' foreach_statement {
180 				$$ = make_foreach_loop_syn_node($3, $5, $7, $9, 0);
181 			}
182 	|	FOREACH '(' expr AS variable HASH_ASSIGN '&' variable ')' foreach_statement {
183 				$$ = make_foreach_loop_syn_node($3, $5, $8, $10, 1);
184 			}
185 	|	DECLARE '(' decl_list ')' statement					{ }
186 	|	DECLARE '(' decl_list ')' ':' top_statement_list ENDDECLARE { }
187 	|	';'													{ $$ = 0; }
188 ;
189 
190 decl_list: IDENT '=' const_value			{  }
191 	|	decl_list ',' IDENT '=' const_value	{  }
192 ;
193 
194 expr_list: expr				{ $$ = make_exp_1(PHP_OP_LIST, 0); $$->exp_node = $1; }
195 	|	expr_list ',' expr	{
196 				PHP_EXP_NODE *last = $1;
197 				while ( last->next) last = last->next;
198 				last->next = make_exp_1(PHP_OP_LIST, 0);
199 				last->next->exp_node = $3;
200 				$$ = $1;
201 			}
202 ;
203 
204 variable_list: variable
205 	|	variable_list ',' variable
206 ;
207 
208 /*
209  This IS implemented. global_var/static itself initialize ptrs as needed
210 */
211 global_var_list: global_var				{ $$ = 0; }
212 	|	global_var_list ',' global_var	{  }
213 ;
214 
215 
216 global_var: VARIABLE	{
217 		const char *varname = get_scope_var_name(g_current_scope, $1->var_si_node->var);
218 		PHP_SCOPE_ITEM *si = get_scope_item(g_current_scope, varname);
219 		PHP_SCOPE_ITEM *gsi = get_scope_item(g_global_scope, varname);
220 		if ( gsi && (gsi->type == PHP_SCOPE_VAR) ) {
221 			free_var_node(si->var);
222 			php_exp_tree_free($1);
223 			gsi->var->ref_count++;
224 			si->var = gsi->var;
225 		} else {
226 			php_report_error(PHP_ERROR, "There is no such global var");
227 		}
228 	}
229 ;
230 
231 static_var_list: static_var				{ $$ = 0; }
232 	|	static_var_list ',' static_var	{  }
233 ;
234 
235 static_var : VARIABLE				{ $1->var_node->flags |= PHP_VARFLAG_STATIC; $$ = $1; }
236 	|	VARIABLE '=' const_value	{
237 			$1->var_node->flags |= PHP_VARFLAG_STATIC; $$ = $1;
238 			value_value_assign(&$1->var_node->value, &$3->val_node);
239 		}
240 ;
241 
242 
243 function_decl_statement:
244 		FUNCTION IDENT {
245 				switch_push_scope_table(make_scope_table());
246 			} '(' parameter_list ')' '{' top_statement_list '}' {
247 				$$ = make_func_decl_syn_node($2, $5);
248 				$$->func_decl->scope = g_current_scope;
249 				$$->func_decl->is_native = 0;
250 				$$->func_decl->code = $8;
251 				switch_pop_scope_table(0);
252 				add_func_2_scope(g_current_scope, $$);
253 				$$ = 0;
254 			}
255 	|	FUNCTION '&' IDENT '(' parameter_list ')' '{' top_statement_list '}' {  }
256 ;
257 
258 parameter_list:
259 		optional_class_type VARIABLE						{ $$ = make_func_param(0, $2, $1, 0); }
260 	|	optional_class_type '&' VARIABLE					{ $$ = make_func_param(0, $3, $1, 1); }
261 	|	parameter_list ',' optional_class_type VARIABLE		{ $$ = make_func_param($1, $4, $3, 0); }
262 	|	parameter_list ',' optional_class_type '&' VARIABLE	{ $$ = make_func_param($1, $5, $3, 1); }
263 	|	/* empty */											{ $$ = 0; }
264 ;
265 
266 optional_class_type:
267 		/* empty */	{ $$[0] = 0; }
268 	|	IDENT
269 ;
270 
271 
272 for_statement:		statement
273 	|	':' top_statement_list ENDFOR ';' { $$ = $2; }
274 ;
275 
276 
277 foreach_statement:	statement
278 	|	':' top_statement_list ENDFOREACH ';' { $$ = $2; }
279 ;
280 
281 for_expr: expr_list
282 	|	/* empty */			{ $$ = 0; }
283 ;
284 
285 elseif_list:
286 		elseif_list ELSEIF '(' expr ')' statement { $$ = add_branch_2_elseif($1, make_ifelse_syn_node($4, $6, 0, 0)); }
287 	|	/* empty */		{ $$ = 0; }
288 ;
289 
290 else_statement:
291 		/* empty */ { $$ = 0; }
292 	|	ELSE statement { $$ = $2; }
293 ;
294 
295 while_statement: statement
296 	|	':' top_statement_list ENDWHILE ';' { $$ = $2; }
297 ;
298 
299 switch_case_list:
300 		'{' case_list '}'				{ $$ = $2; }
301 	|	'{' ';' case_list '}'			{ $$ = $3; }
302 	|	':' case_list ENDSWITCH ';'		{ $$ = $2; }
303 	|	':' ';' case_list ENDSWITCH ';'	{ $$ = $3; }
304 ;
305 
306 case_list:
307 		/* empty */	{  $$ = 0; }
308 	|	case_list case_list_item case_separator top_statement_list {
309 			$2->tree_node.syn_right = $4;
310 			if ( $1 ) {
311 				PHP_EXP_NODE *last = $1;
312 				while ( last->next) last = last->next;
313 				last->next = make_exp_1(PHP_OP_LIST, 0);
314 				last->next->exp_node = $2;
315 				$$ = $1;
316 			} else {
317 				$$ = make_exp_1(PHP_OP_LIST, 0);
318 				$$->exp_node = $2;
319 			}
320 		}
321 ;
322 
323 case_list_item: CASE expr	{ $$ = make_exp_2(PHP_OP_LIST, $2, 0); }
324 	| DEFAULT				{ $$ = make_exp_2(PHP_OP_LIST, 0, 0); }
325 ;
326 
327 case_separator:	':'
328 	|	';'
329 ;
330 
331 const_value:
332 		FNUMBER
333 	|	DNUMBER
334 	|   STRING
335 	|	IDENT { $$ = make_known_const($1); }
336 ;
337 
338 variable:	deref_variable
339 	|	IDENT CLASS_SCOPE IDENT					{ $$ = make_exp_2(PHP_OP_CLASS_DEREF, make_const_exp_str($1, 0), make_const_exp_str($3, 0)); }
340 	|	deref_variable OBJECT_OPERATOR IDENT	{ $$ = make_exp_2(PHP_OP_OBJECT_DEREF, $1, make_const_exp_str($3, 0)); }
341 ;
342 
343 
344 deref_variable: VARIABLE
345 	|	deref_variable '[' ']'			{ $$ = make_exp_2(PHP_OP_ARRAY_BY_KEY, $1, 0); }
346 	|	deref_variable '[' expr ']'		{ $$ = make_exp_2(PHP_OP_ARRAY_BY_KEY, $1, $3);}
347 	|	deref_variable '{' expr '}'		{ $$ = make_exp_2(PHP_OP_ARRAY_BY_KEY, $1, $3);}
348 	|	'$' '{' expr '}'				{ $$ = make_exp_1(PHP_OP_VAR_BY_EXP, $3); }
349 ;
350 
351 function_call:
352 		IDENT	'(' func_param_list ')'									{ $$ = make_func_call_exp($1, $3); }
353 	|	deref_variable CLASS_SCOPE IDENT '(' func_param_list ')'		{ }
354 	|	deref_variable OBJECT_OPERATOR IDENT '(' func_param_list ')'	{ }
355 ;
356 
357 func_param_list: expr						{ $$ = make_func_call_param_list(); func_call_add_expr($$->var_node, $1, 0); }
358 	|	'&' variable						{ $$ = make_func_call_param_list(); func_call_add_expr($$->var_node, $2, 1); }
359 	|	func_param_list ',' expr			{ $$ = $1; func_call_add_expr($$->var_node, $3, 0); }
360 	|	func_param_list ',' '&' variable	{ $$ = $1; func_call_add_expr($$->var_node, $4, 1); }
361 	|	/* empty */							{ $$ = make_func_call_param_list(); }
362 ;
363 
364 
365 expr:
366 		LIST '(' assignment_list ')' '=' expr { }
367 	|	variable
368 	|	variable '=' expr			{ $$ = make_exp_2(PHP_OP_ASS, $1, $3); }
369 	|	function_call				{ $$ = $1; }
370 	|	variable '=' '&' variable	{ $$ = make_exp_2(PHP_MAKE_REF, $1, $4); }
371 /*
372 	|	NEW class_name_reference ctor_arguments { }
373 	|	CLONE expr {  }
374 */
375 	|	variable PLUS_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_ADD, $1, $3)); }
376 	|	variable MINUS_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_SUB, $1, $3)); }
377 	|	variable MUL_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_MUL, $1, $3)); }
378 	|	variable DIV_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_DIV, $1, $3)); }
379 	|	variable CONCAT_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_CAT, $1, $3)); }
380 	|	variable MOD_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_REM, $1, $3)); }
381 	|	variable AND_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_AND, $1, $3)); }
382 	|	variable OR_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_OR, $1, $3)); }
383 	|	variable XOR_EQ expr		{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_XOR, $1, $3)); }
384 	|	variable SL_EQ expr			{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_SHL, $1, $3)); }
385 	|	variable SR_EQ expr			{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_SHR, $1, $3)); }
386 	/* ++var and var++ looks same to me */
387 	|	variable INC				{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_ADD, $1, make_const_exp_dnum(1))); }
388 	|	INC variable				{ $$ = make_exp_2_self(PHP_OP_ASS, $2, make_exp_2(PHP_OP_ADD, $2, make_const_exp_dnum(1))); }
389 	|	variable DEC				{ $$ = make_exp_2_self(PHP_OP_ASS, $1, make_exp_2(PHP_OP_SUB, $1, make_const_exp_dnum(1))); }
390 	|	DEC variable				{ $$ = make_exp_2_self(PHP_OP_ASS, $2, make_exp_2(PHP_OP_SUB, $2, make_const_exp_dnum(1))); }
391 
392 	|	expr BOOLEAN_OR expr		{ $$ = make_exp_2(PHP_OP_LOG_OR, $1, $3); }
393 	|	expr BOOLEAN_AND expr		{ $$ = make_exp_2(PHP_OP_LOG_AND, $1, $3); }
394 	|	expr LOG_OR expr			{ $$ = make_exp_2(PHP_OP_LOG_OR, $1, $3); }
395 	|	expr LOG_AND expr			{ $$ = make_exp_2(PHP_OP_LOG_AND, $1, $3); }
396 	|	expr LOG_XOR expr			{ $$ = make_exp_2(PHP_OP_LOG_XOR, $1, $3); }
397 	|	expr '|' expr				{ $$ = make_exp_2(PHP_OP_OR, $1, $3); }
398 	|	expr '&' expr				{ $$ = make_exp_2(PHP_OP_AND, $1, $3); }
399 	|	expr '^' expr				{ $$ = make_exp_2(PHP_OP_XOR, $1, $3); }
400 	|	expr '.' expr				{ $$ = make_exp_2(PHP_OP_CAT, $1, $3); }
401 	|	expr '+' expr				{ $$ = make_exp_2(PHP_OP_ADD, $1, $3); }
402 	|	expr '-' expr				{ $$ = make_exp_2(PHP_OP_SUB, $1, $3); }
403 	|	expr '*' expr				{ $$ = make_exp_2(PHP_OP_MUL, $1, $3); }
404 	|	expr '/' expr				{ $$ = make_exp_2(PHP_OP_DIV, $1, $3); }
405 	|	expr '%' expr				{ $$ = make_exp_2(PHP_OP_REM, $1, $3); }
406 	|	expr SL expr				{ $$ = make_exp_2(PHP_OP_SHL, $1, $3); }
407 	|	expr SR expr				{ $$ = make_exp_2(PHP_OP_SHR, $1, $3); }
408 	|	'+' expr					{ $$ = $2; }
409 	|	'-' expr					{ $$ = make_exp_2(PHP_OP_SUB, make_const_exp_dnum(0), $2); }
410 	|	'!' expr					{ $$ = make_exp_1(PHP_OP_LOG_NOT, $2); }
411 	|	'~' expr					{ $$ = make_exp_1(PHP_OP_NOT, $2); }
412 	|	expr IS_IDENTICAL expr		{ $$ = make_exp_2(PHP_OP_SAME, $1, $3); }
413 	|	expr IS_NOIDENTICAL expr	{ $$ = make_exp_2(PHP_OP_NOT_SAME, $1, $3); }
414 	|	expr IS_EQ expr				{ $$ = make_exp_2(PHP_OP_EQ, $1, $3); }
415 	|	expr IS_NOEQUAL expr		{ $$ = make_exp_2(PHP_OP_NEQ, $1, $3); }
416 	|	expr '<' expr				{ $$ = make_exp_2(PHP_OP_LWR, $1, $3); }
417 	|	expr IS_SMALLER_OR_EQ expr	{ $$ = make_exp_2(PHP_OP_LWR_EQ, $1, $3); }
418 	|	expr '>' expr				{ $$ = make_exp_2(PHP_OP_GRT, $1, $3); }
419 	|	expr IS_GREATER_OR_EQ expr	{ $$ = make_exp_2(PHP_OP_GRT_EQ, $1, $3); }
420 	|	'(' expr ')'				{ $$ = $2; }
421 	|	expr '?' expr ':' expr		{ $$ = make_exp_2(PHP_OP_MUX, $3, $5); $$->exp_node = $1; }
422 	|	INT_CAST expr				{ $$ = make_exp_1(PHP_OP_CAST_INT, $2); }
423 	|	DOUBLE_CAST expr			{ $$ = make_exp_1(PHP_OP_CAST_FLOAT, $2); }
424 	|	STRING_CAST expr			{ $$ = make_exp_1(PHP_OP_CAST_STR, $2); }
425 	|	BOOL_CAST expr				{ $$ = make_exp_1(PHP_OP_CAST_BOOL, $2); }
426 /*	|	ARRAY_CAST expr		{  } */
427 /*	|	OBJECT_CAST expr	{  } */
428 	|	UNSET_CAST expr	{  }
429 	|	EXIT exit_expr	{  }
430 	|	'@' expr					{ $$ = $2; }
431 
432 	|	const_value					{ $$ = $1; }
433 	|	ARRAY '(' array_pair_list ')' { $$ = make_exp_1(PHP_OP_ARRAY, $3); }
434 	|	PRINT expr				{ $$ = make_exp_1(PHP_OP_PRINT, $2); }
435 ;
436 
437 exit_expr: '(' expr ')'	{ $$ = $2; }
438 	|	'(' ')'			{ $$ = 0; }
439 	|	/* empty */		{ $$ = 0; }
440 ;
441 
442 assignment_list: assignment_list_element
443 	|	assignment_list ',' assignment_list_element
444 ;
445 
446 
447 assignment_list_element: variable		{ /*$$ = make_assign_node($1);*/ }
448 	|	LIST '(' assignment_list ')'	{ $$ = $3; }
449 	|	/* empty */						{ /*$$ = make_assign_node(0);*/ }
450 ;
451 
452 array_pair_list: array_elem				{ $$ = make_exp_1(PHP_OP_LIST, 0); $$->exp_node = $1; }
453 	| array_pair_list ',' array_elem	{
454 				PHP_EXP_NODE *last = $1;
455 				while ( last->next) last = last->next;
456 				last->next = make_exp_1(PHP_OP_LIST, 0);
457 				last->next->exp_node = $3;
458 				$$ = $1;
459 			}
460 ;
461 
462 array_elem : expr						{ $$ = make_exp_1(PHP_OP_ARRAY_PAIR, $1); }
463 	| expr HASH_ASSIGN expr				{ $$ = make_exp_2(PHP_OP_ARRAY_PAIR, $1, $3); }
464 	| expr HASH_ASSIGN '&' variable		{ $$ = make_exp_2(PHP_OP_ARRAY_REF_PAIR, $1, $4); }
465 	| '&' variable						{ $$ = make_exp_1(PHP_OP_ARRAY_REF_PAIR, $2); }
466 ;
467 
468 
469