Upstream tarball 20080304
[amule.git] / src / webserver / src / php_parser.y
blob4cb9639fd55fcc167fa5ba115cb54acb21346e1d
1 %{
2 //
3 // This file is part of the aMule Project.
4 //
5 // Copyright (c) 2003-2006 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Copyright (C) 2005-2006Froenchenko Leonid ( lfroen@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.
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.
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
27 #include <stdio.h>
28 #include <string.h>
30 #include "php_syntree.h"
32 int yylex();
34 // add item to syntree list
35 PHP_SYN_NODE *add_statement_2_list(PHP_SYN_NODE *list, PHP_SYN_NODE *st)
37 if ( st && list) {
38 PHP_SYN_NODE *last = list;
39 while ( last->next_node ) {
40 last = last->next_node;
42 last->next_node = st;
43 return list;
44 } else if ( st ) {
45 return st;
46 } else {
47 return list;
51 PHP_SYN_NODE *add_branch_2_elseif(PHP_SYN_NODE *list, PHP_SYN_NODE *branch)
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;
58 curr_if->node_if.code_else = branch;
59 return list;
60 } else {
61 return branch;
67 %union {
68 PHP_SYN_NODE *syn_node;
69 PHP_EXP_NODE *exp_node;
71 char str_val[256];
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
88 All my tokens
90 %token FNUMBER DNUMBER STRING IDENT VARIABLE
92 %token ECHO
93 %token EXIT
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
104 %token CLASS_SCOPE
107 Things with precedence
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
132 %left ELSEIF
133 %left ELSE
134 %left ENDIF
136 %right STATIC ABSTRACT FINAL PRIVATE PROTECTED PUBLIC
138 %token START_SCRIPT END_SCRIPT
140 %% /* Rules */
142 program_tree: START_SCRIPT top_statement_list END_SCRIPT { g_syn_tree_top = $2; }
145 top_statement_list:
146 top_statement_list top_statement { $$ = add_statement_2_list($1, $2); }
147 | /* empty */ { $$ = 0; }
151 top_statement:
152 statement
153 | START_SCRIPT top_statement_list END_SCRIPT { $$ = $2; }
154 | function_decl_statement
155 /* | class_decl_statement */
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 | 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 { }
187 | ';' { $$ = 0; }
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;
200 $$ = $1;
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++;
224 si->var = gsi->var;
225 } else {
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:
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;
255 | FUNCTION '&' IDENT '(' parameter_list ')' '{' top_statement_list '}' { }
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; }
266 optional_class_type:
267 /* empty */ { $$[0] = 0; }
268 | IDENT
272 for_statement: statement
273 | ':' top_statement_list ENDFOR ';' { $$ = $2; }
277 foreach_statement: statement
278 | ':' top_statement_list ENDFOREACH ';' { $$ = $2; }
281 for_expr: expr_list
282 | /* empty */ { $$ = 0; }
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; }
290 else_statement:
291 /* empty */ { $$ = 0; }
292 | ELSE statement { $$ = $2; }
295 while_statement: statement
296 | ':' top_statement_list ENDWHILE ';' { $$ = $2; }
299 switch_case_list:
300 '{' case_list '}' { $$ = $2; }
301 | '{' ';' case_list '}' { $$ = $3; }
302 | ':' case_list ENDSWITCH ';' { $$ = $2; }
303 | ':' ';' case_list ENDSWITCH ';' { $$ = $3; }
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;
323 case_list_item: CASE expr { $$ = make_exp_2(PHP_OP_LIST, $2, 0); }
324 | DEFAULT { $$ = make_exp_2(PHP_OP_LIST, 0, 0); }
327 case_separator: ':'
328 | ';'
331 const_value:
332 FNUMBER
333 | DNUMBER
334 | STRING
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); }
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 ')' { }
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(); }
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); }
372 | NEW class_name_reference ctor_arguments { }
373 | CLONE expr { }
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 { }
429 | EXIT exit_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;
458 $$ = $1;
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); }