3 // This file is part of the aMule Project.
5 // Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (C) 2005-2006Froenchenko Leonid ( lfroen@amule.org )
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.
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.
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.
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
30 #include "php_syntree.h"
34 // add item to syntree list
35 PHP_SYN_NODE
*add_statement_2_list
(PHP_SYN_NODE
*list
, PHP_SYN_NODE
*st
)
38 PHP_SYN_NODE
*last
= list
;
39 while
( last
->next_node
) {
40 last
= last
->next_node
;
51 PHP_SYN_NODE
*add_branch_2_elseif
(PHP_SYN_NODE
*list
, PHP_SYN_NODE
*branch
)
54 PHP_SYN_NODE
*curr_if
= list
;
55 while
( curr_if
->node_if.code_else
) {
56 curr_if
= curr_if
->node_if.code_else
;
58 curr_if
->node_if.code_else
= branch
;
68 PHP_SYN_NODE
*syn_node
;
69 PHP_EXP_NODE
*exp_node
;
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
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
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
85 %type
<str_val
> IDENT optional_class_type
90 %token FNUMBER DNUMBER STRING IDENT VARIABLE
95 %token IF DO WHILE ENDWHILE FOR ENDFOR FOREACH ENDFOREACH
97 %token DECLARE ENDDECLARE AS CONST GLOBAL UNSET ISSET EMPTY
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
107 Things with precedence
111 %left
'=' PLUS_EQ MINUS_EQ MUL_EQ DIV_EQ CONCAT_EQ MOD_EQ AND_EQ OR_EQ XOR_EQ SL_EQ SR_EQ
121 %nonassoc IS_EQ IS_NOEQUAL IS_IDENTICAL IS_NOIDENTICAL
122 %nonassoc
'<' IS_SMALLER_OR_EQ
'>' IS_GREATER_OR_EQ
128 %right
'~' INC DEC INT_CAST DOUBLE_CAST STRING_CAST ARRAY_CAST OBJECT_CAST BOOL_CAST UNSET_CAST
'@'
136 %right STATIC ABSTRACT FINAL PRIVATE PROTECTED PUBLIC
138 %token START_SCRIPT END_SCRIPT
142 program_tree: START_SCRIPT top_statement_list END_SCRIPT
{ g_syn_tree_top
= $2; }
146 top_statement_list top_statement
{ $$
= add_statement_2_list
($1, $2); }
147 |
/* empty */ { $$
= 0; }
153 | START_SCRIPT top_statement_list END_SCRIPT
{ $$
= $2; }
154 | function_decl_statement
155 /* | class_decl_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 | 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);
179 | FOREACH
'(' expr AS variable HASH_ASSIGN variable
')' foreach_statement
{
180 $$
= make_foreach_loop_syn_node
($3, $5, $7, $9, 0);
182 | FOREACH
'(' expr AS variable HASH_ASSIGN
'&' variable
')' foreach_statement
{
183 $$
= make_foreach_loop_syn_node
($3, $5, $8, $10, 1);
185 | DECLARE
'(' decl_list
')' statement
{ }
186 | DECLARE
'(' decl_list
')' ':' top_statement_list ENDDECLARE
{ }
190 decl_list: IDENT
'=' const_value
{ }
191 | decl_list
',' IDENT
'=' const_value
{ }
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;
204 variable_list: variable
205 | variable_list
',' variable
209 This IS implemented. global_var/static itself initialize ptrs as needed
211 global_var_list: global_var
{ $$
= 0; }
212 | global_var_list
',' global_var
{ }
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
++;
226 php_report_error
(PHP_ERROR
, "There is no such global var");
231 static_var_list: static_var
{ $$
= 0; }
232 | static_var_list
',' static_var
{ }
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
);
243 function_decl_statement:
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
, $$
);
255 | FUNCTION
'&' IDENT
'(' parameter_list
')' '{' top_statement_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; }
267 /* empty */ { $$
[0] = 0; }
272 for_statement: statement
273 |
':' top_statement_list ENDFOR
';' { $$
= $2; }
277 foreach_statement: statement
278 |
':' top_statement_list ENDFOREACH
';' { $$
= $2; }
282 |
/* empty */ { $$
= 0; }
286 elseif_list ELSEIF
'(' expr
')' statement
{ $$
= add_branch_2_elseif
($1, make_ifelse_syn_node
($4, $6, 0, 0)); }
287 |
/* empty */ { $$
= 0; }
291 /* empty */ { $$
= 0; }
292 | ELSE statement
{ $$
= $2; }
295 while_statement: statement
296 |
':' top_statement_list ENDWHILE
';' { $$
= $2; }
300 '{' case_list
'}' { $$
= $2; }
301 |
'{' ';' case_list
'}' { $$
= $3; }
302 |
':' case_list ENDSWITCH
';' { $$
= $2; }
303 |
':' ';' case_list ENDSWITCH
';' { $$
= $3; }
307 /* empty */ { $$
= 0; }
308 | case_list case_list_item case_separator top_statement_list
{
309 $2->tree_node.syn_right
= $4;
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;
317 $$
= make_exp_1
(PHP_OP_LIST
, 0);
323 case_list_item: CASE expr
{ $$
= make_exp_2
(PHP_OP_LIST
, $2, 0); }
324 | DEFAULT
{ $$
= make_exp_2
(PHP_OP_LIST
, 0, 0); }
335 | IDENT
{ $$
= make_known_const
($1); }
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)); }
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); }
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
')' { }
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
(); }
366 LIST
'(' assignment_list
')' '=' expr
{ }
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); }
372 | NEW class_name_reference ctor_arguments { }
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))); }
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
{ }
430 |
'@' expr
{ $$
= $2; }
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); }
437 exit_expr: '(' expr
')' { $$
= $2; }
438 |
'(' ')' { $$
= 0; }
439 |
/* empty */ { $$
= 0; }
442 assignment_list: assignment_list_element
443 | assignment_list
',' assignment_list_element
447 assignment_list_element: variable
{ /*$$ = make_assign_node($1);*/ }
448 | LIST
'(' assignment_list
')' { $$
= $3; }
449 |
/* empty */ { /*$$ = make_assign_node(0);*/ }
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;
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); }