diff options
author | Ludovic Pouzenc <ludovic@pouzenc.fr> | 2012-08-01 08:29:21 +0000 |
---|---|---|
committer | Ludovic Pouzenc <ludovic@pouzenc.fr> | 2012-08-01 08:29:21 +0000 |
commit | e73d3ed6011892b053b75419a43317c6a07bc763 (patch) | |
tree | 68f07771560b856e10bd464163c46cbe566df2a1 | |
parent | cfdc1bc2f770341db269279b160d9210cd4b923c (diff) | |
download | 2012-php-weave-e73d3ed6011892b053b75419a43317c6a07bc763.tar.gz 2012-php-weave-e73d3ed6011892b053b75419a43317c6a07bc763.tar.bz2 2012-php-weave-e73d3ed6011892b053b75419a43317c6a07bc763.zip |
Premier commit.
nikic-PHP-Parser est un outil très prometteur.
Le test test01-parsing inclu dans l'AST principal tous les include(<String>) ou string est un chemin relatif facile à résoudre.
git-svn-id: file:///var/svn/2012-php-weave/trunk@2 d972a294-176a-4cf9-8ea1-fcd5b0c30f5c
-rwxr-xr-x | composer.phar | bin | 0 -> 544342 bytes | |||
-rw-r--r-- | recherches/grammaire/url.txt | 10 | ||||
-rw-r--r-- | recherches/grammaire/zend_language_parser.y | 1245 | ||||
-rw-r--r-- | recherches/grammaire/zend_language_scanner.l | 2414 | ||||
-rw-r--r-- | recherches/parsers/lime.tar.gz | bin | 0 -> 55579 bytes | |||
-rw-r--r-- | recherches/parsers/nikic-PHP-Parser-v0.9.2.txt | 1 | ||||
-rw-r--r-- | tests/test01-parsing/src/composer.json | 6 | ||||
-rwxr-xr-x | tests/test01-parsing/src/get_deps.sh | 2 | ||||
-rw-r--r-- | tests/test01-parsing/src/php-weave/main.php | 64 | ||||
-rw-r--r-- | tests/test01-parsing/src/php-weave/to_parse.php | 5 | ||||
-rw-r--r-- | tests/test01-parsing/src/php-weave/visitors.inc.php | 91 |
11 files changed, 3838 insertions, 0 deletions
diff --git a/composer.phar b/composer.phar Binary files differnew file mode 100755 index 0000000..f9592cc --- /dev/null +++ b/composer.phar diff --git a/recherches/grammaire/url.txt b/recherches/grammaire/url.txt new file mode 100644 index 0000000..361f7a8 --- /dev/null +++ b/recherches/grammaire/url.txt @@ -0,0 +1,10 @@ +https://svn.php.net/repository/php/php-src/trunk/Zend/zend_language_parser.y +(utilise re2c) + +http://stackoverflow.com/questions/8795845/flex-bison-php-ast-generation + + +PHP parser in PHP : +http://stackoverflow.com/questions/5586358/any-decent-php-parser-written-in-php + + diff --git a/recherches/grammaire/zend_language_parser.y b/recherches/grammaire/zend_language_parser.y new file mode 100644 index 0000000..d0730b7 --- /dev/null +++ b/recherches/grammaire/zend_language_parser.y @@ -0,0 +1,1245 @@ +%{ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andi Gutmans <andi@zend.com> | + | Zeev Suraski <zeev@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +/* + * LALR shift/reduce conflicts and how they are resolved: + * + * - 2 shift/reduce conflicts due to the dangling elseif/else ambiguity. Solved by shift. + * + */ + + +#include "zend_compile.h" +#include "zend.h" +#include "zend_list.h" +#include "zend_globals.h" +#include "zend_API.h" +#include "zend_constants.h" + +#define YYSIZE_T size_t +#define yytnamerr zend_yytnamerr +static YYSIZE_T zend_yytnamerr(char*, const char*); + +#define YYERROR_VERBOSE +#define YYSTYPE znode +#ifdef ZTS +# define YYPARSE_PARAM tsrm_ls +# define YYLEX_PARAM tsrm_ls +#endif + + +%} + +%pure_parser +%expect 3 + +%token END 0 "end of file" +%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE +%token T_INCLUDE "include (T_INCLUDE)" +%token T_INCLUDE_ONCE "include_once (T_INCLUDE_ONCE)" +%token T_EVAL "eval (T_EVAL)" +%token T_REQUIRE "require (T_REQUIRE)" +%token T_REQUIRE_ONCE "require_once (T_REQUIRE_ONCE)" +%left ',' +%left T_LOGICAL_OR +%token T_LOGICAL_OR "or (T_LOGICAL_OR)" +%left T_LOGICAL_XOR +%token T_LOGICAL_XOR "xor (T_LOGICAL_XOR)" +%left T_LOGICAL_AND +%token T_LOGICAL_AND "and (T_LOGICAL_AND)" +%right T_PRINT +%token T_PRINT "print (T_PRINT)" +%left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL +%token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)" +%token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)" +%token T_MUL_EQUAL "*= (T_MUL_EQUAL)" +%token T_DIV_EQUAL "/= (T_DIV_EQUAL)" +%token T_CONCAT_EQUAL ".= (T_CONCAT_EQUAL)" +%token T_MOD_EQUAL "%= (T_MOD_EQUAL)" +%token T_AND_EQUAL "&= (T_AND_EQUAL)" +%token T_OR_EQUAL "|= (T_OR_EQUAL)" +%token T_XOR_EQUAL "^= (T_XOR_EQUAL)" +%token T_SL_EQUAL "<<= (T_SL_EQUAL)" +%token T_SR_EQUAL ">>= (T_SR_EQUAL)" +%left '?' ':' +%left T_BOOLEAN_OR +%token T_BOOLEAN_OR "|| (T_BOOLEAN_OR)" +%left T_BOOLEAN_AND +%token T_BOOLEAN_AND "&& (T_BOOLEAN_AND)" +%left '|' +%left '^' +%left '&' +%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL +%token T_IS_EQUAL "== (T_IS_EQUAL)" +%token T_IS_NOT_EQUAL "!= (T_IS_NOT_EQUAL)" +%token T_IS_IDENTICAL "=== (T_IS_IDENTICAL)" +%token T_IS_NOT_IDENTICAL "!== (T_IS_NOT_IDENTICAL)" +%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL +%token T_IS_SMALLER_OR_EQUAL "<= (T_IS_SMALLER_OR_EQUAL)" +%token T_IS_GREATER_OR_EQUAL ">= (T_IS_GREATER_OR_EQUAL)" +%left T_SL T_SR +%token T_SL "<< (T_SL)" +%token T_SR ">> (T_SR)" +%left '+' '-' '.' +%left '*' '/' '%' +%right '!' +%nonassoc T_INSTANCEOF +%token T_INSTANCEOF "instanceof (T_INSTANCEOF)" +%right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@' +%token T_INC "++ (T_INC)" +%token T_DEC "-- (T_DEC)" +%token T_INT_CAST "(int) (T_INT_CAST)" +%token T_DOUBLE_CAST "(double) (T_DOUBLE_CAST)" +%token T_STRING_CAST "(string) (T_STRING_CAST)" +%token T_ARRAY_CAST "(array) (T_ARRAY_CAST)" +%token T_OBJECT_CAST "(object) (T_OBJECT_CAST)" +%token T_BOOL_CAST "(bool) (T_BOOL_CAST)" +%token T_UNSET_CAST "(unset) (T_UNSET_CAST)" +%right '[' +%nonassoc T_NEW T_CLONE +%token T_NEW "new (T_NEW)" +%token T_CLONE "clone (T_CLONE)" +%token T_EXIT "exit (T_EXIT)" +%token T_IF "if (T_IF)" +%left T_ELSEIF +%token T_ELSEIF "elseif (T_ELSEIF)" +%left T_ELSE +%token T_ELSE "else (T_ELSE)" +%left T_ENDIF +%token T_ENDIF "endif (T_ENDIF)" +%token T_LNUMBER "integer number (T_LNUMBER)" +%token T_DNUMBER "floating-point number (T_DNUMBER)" +%token T_STRING "identifier (T_STRING)" +%token T_STRING_VARNAME "variable name (T_STRING_VARNAME)" +%token T_VARIABLE "variable (T_VARIABLE)" +%token T_NUM_STRING "number (T_NUM_STRING)" +%token T_INLINE_HTML +%token T_CHARACTER +%token T_BAD_CHARACTER +%token T_ENCAPSED_AND_WHITESPACE "quoted-string and whitespace (T_ENCAPSED_AND_WHITESPACE)" +%token T_CONSTANT_ENCAPSED_STRING "quoted-string (T_CONSTANT_ENCAPSED_STRING)" +%token T_ECHO "echo (T_ECHO)" +%token T_DO "do (T_DO)" +%token T_WHILE "while (T_WHILE)" +%token T_ENDWHILE "endwhile (T_ENDWHILE)" +%token T_FOR "for (T_FOR)" +%token T_ENDFOR "endfor (T_ENDFOR)" +%token T_FOREACH "foreach (T_FOREACH)" +%token T_ENDFOREACH "endforeach (T_ENDFOREACH)" +%token T_DECLARE "declare (T_DECLARE)" +%token T_ENDDECLARE "enddeclare (T_ENDDECLARE)" +%token T_AS "as (T_AS)" +%token T_SWITCH "switch (T_SWITCH)" +%token T_ENDSWITCH "endswitch (T_ENDSWITCH)" +%token T_CASE "case (T_CASE)" +%token T_DEFAULT "default (T_DEFAULT)" +%token T_BREAK "break (T_BREAK)" +%token T_CONTINUE "continue (T_CONTINUE)" +%token T_GOTO "goto (T_GOTO)" +%token T_FUNCTION "function (T_FUNCTION)" +%token T_CONST "const (T_CONST)" +%token T_RETURN "return (T_RETURN)" +%token T_TRY "try (T_TRY)" +%token T_CATCH "catch (T_CATCH)" +%token T_THROW "throw (T_THROW)" +%token T_USE "use (T_USE)" +%token T_INSTEADOF "insteadof (T_INSTEADOF)" +%token T_GLOBAL "global (T_GLOBAL)" +%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC +%token T_STATIC "static (T_STATIC)" +%token T_ABSTRACT "abstract (T_ABSTRACT)" +%token T_FINAL "final (T_FINAL)" +%token T_PRIVATE "private (T_PRIVATE)" +%token T_PROTECTED "protected (T_PROTECTED)" +%token T_PUBLIC "public (T_PUBLIC)" +%token T_VAR "var (T_VAR)" +%token T_UNSET "unset (T_UNSET)" +%token T_ISSET "isset (T_ISSET)" +%token T_EMPTY "empty (T_EMPTY)" +%token T_HALT_COMPILER "__halt_compiler (T_HALT_COMPILER)" +%token T_CLASS "class (T_CLASS)" +%token T_TRAIT "trait (T_TRAIT)" +%token T_INTERFACE "interface (T_INTERFACE)" +%token T_EXTENDS "extends (T_EXTENDS)" +%token T_IMPLEMENTS "implements (T_IMPLEMENTS)" +%token T_OBJECT_OPERATOR "-> (T_OBJECT_OPERATOR)" +%token T_DOUBLE_ARROW "=> (T_DOUBLE_ARROW)" +%token T_LIST "list (T_LIST)" +%token T_ARRAY "array (T_ARRAY)" +%token T_CALLABLE "callable (T_CALLABLE)" +%token T_CLASS_C "__CLASS__ (T_CLASS_C)" +%token T_TRAIT_C "__TRAIT__ (T_TRAIT_C)" +%token T_METHOD_C "__METHOD__ (T_METHOD_C)" +%token T_FUNC_C "__FUNCTION__ (T_FUNC_C)" +%token T_LINE "__LINE__ (T_LINE)" +%token T_FILE "__FILE__ (T_FILE)" +%token T_COMMENT "comment (T_COMMENT)" +%token T_DOC_COMMENT "doc comment (T_DOC_COMMENT)" +%token T_OPEN_TAG "open tag (T_OPEN_TAG)" +%token T_OPEN_TAG_WITH_ECHO "open tag with echo (T_OPEN_TAG_WITH_ECHO)" +%token T_CLOSE_TAG "close tag (T_CLOSE_TAG)" +%token T_WHITESPACE "whitespace (T_WHITESPACE)" +%token T_START_HEREDOC "heredoc start (T_START_HEREDOC)" +%token T_END_HEREDOC "heredoc end (T_END_HEREDOC)" +%token T_DOLLAR_OPEN_CURLY_BRACES "${ (T_DOLLAR_OPEN_CURLY_BRACES)" +%token T_CURLY_OPEN "{$ (T_CURLY_OPEN)" +%token T_PAAMAYIM_NEKUDOTAYIM ":: (T_PAAMAYIM_NEKUDOTAYIM)" +%token T_NAMESPACE "namespace (T_NAMESPACE)" +%token T_NS_C "__NAMESPACE__ (T_NS_C)" +%token T_DIR "__DIR__ (T_DIR)" +%token T_NS_SEPARATOR "\\ (T_NS_SEPARATOR)" + +%% /* Rules */ + +start: + top_statement_list { zend_do_end_compilation(TSRMLS_C); } +; + +top_statement_list: + top_statement_list { zend_do_extended_info(TSRMLS_C); } top_statement { HANDLE_INTERACTIVE(); } + | /* empty */ +; + +namespace_name: + T_STRING { $$ = $1; } + | namespace_name T_NS_SEPARATOR T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); } +; + +top_statement: + statement { zend_verify_namespace(TSRMLS_C); } + | function_declaration_statement { zend_verify_namespace(TSRMLS_C); zend_do_early_binding(TSRMLS_C); } + | class_declaration_statement { zend_verify_namespace(TSRMLS_C); zend_do_early_binding(TSRMLS_C); } + | T_HALT_COMPILER '(' ')' ';' { zend_do_halt_compiler_register(TSRMLS_C); YYACCEPT; } + | T_NAMESPACE namespace_name ';' { zend_do_begin_namespace(&$2, 0 TSRMLS_CC); } + | T_NAMESPACE namespace_name '{' { zend_do_begin_namespace(&$2, 1 TSRMLS_CC); } + top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } + | T_NAMESPACE '{' { zend_do_begin_namespace(NULL, 1 TSRMLS_CC); } + top_statement_list '}' { zend_do_end_namespace(TSRMLS_C); } + | T_USE use_declarations ';' { zend_verify_namespace(TSRMLS_C); } + | constant_declaration ';' { zend_verify_namespace(TSRMLS_C); } +; + +use_declarations: + use_declarations ',' use_declaration + | use_declaration +; + +use_declaration: + namespace_name { zend_do_use(&$1, NULL, 0 TSRMLS_CC); } + | namespace_name T_AS T_STRING { zend_do_use(&$1, &$3, 0 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { zend_do_use(&$2, NULL, 1 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name T_AS T_STRING { zend_do_use(&$2, &$4, 1 TSRMLS_CC); } +; + +constant_declaration: + constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar { zend_do_declare_constant(&$2, &$4 TSRMLS_CC); } +; + +inner_statement_list: + inner_statement_list { zend_do_extended_info(TSRMLS_C); } inner_statement { HANDLE_INTERACTIVE(); } + | /* empty */ +; + + +inner_statement: + statement + | function_declaration_statement + | class_declaration_statement + | T_HALT_COMPILER '(' ')' ';' { zend_error(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope"); } +; + + +statement: + unticked_statement { DO_TICKS(); } + | T_STRING ':' { zend_do_label(&$1 TSRMLS_CC); } +; + +unticked_statement: + '{' inner_statement_list '}' + | T_IF '(' expr ')' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } statement { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } elseif_list else_single { zend_do_if_end(TSRMLS_C); } + | T_IF '(' expr ')' ':' { zend_do_if_cond(&$3, &$4 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$4, 1 TSRMLS_CC); } new_elseif_list new_else_single T_ENDIF ';' { zend_do_if_end(TSRMLS_C); } + | T_WHILE '(' { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' { zend_do_while_cond(&$4, &$5 TSRMLS_CC); } while_statement { zend_do_while_end(&$1, &$5 TSRMLS_CC); } + | T_DO { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_do_while_begin(TSRMLS_C); } statement T_WHILE '(' { $5.u.op.opline_num = get_next_op_number(CG(active_op_array)); } expr ')' ';' { zend_do_do_while_end(&$1, &$5, &$7 TSRMLS_CC); } + | T_FOR + '(' + for_expr + ';' { zend_do_free(&$3 TSRMLS_CC); $4.u.op.opline_num = get_next_op_number(CG(active_op_array)); } + for_expr + ';' { zend_do_extended_info(TSRMLS_C); zend_do_for_cond(&$6, &$7 TSRMLS_CC); } + for_expr + ')' { zend_do_free(&$9 TSRMLS_CC); zend_do_for_before_statement(&$4, &$7 TSRMLS_CC); } + for_statement { zend_do_for_end(&$7 TSRMLS_CC); } + | T_SWITCH '(' expr ')' { zend_do_switch_cond(&$3 TSRMLS_CC); } switch_case_list { zend_do_switch_end(&$6 TSRMLS_CC); } + | T_BREAK ';' { zend_do_brk_cont(ZEND_BRK, NULL TSRMLS_CC); } + | T_BREAK expr ';' { zend_do_brk_cont(ZEND_BRK, &$2 TSRMLS_CC); } + | T_CONTINUE ';' { zend_do_brk_cont(ZEND_CONT, NULL TSRMLS_CC); } + | T_CONTINUE expr ';' { zend_do_brk_cont(ZEND_CONT, &$2 TSRMLS_CC); } + | T_RETURN ';' { zend_do_return(NULL, 0 TSRMLS_CC); } + | T_RETURN expr_without_variable ';' { zend_do_return(&$2, 0 TSRMLS_CC); } + | T_RETURN variable ';' { zend_do_return(&$2, 1 TSRMLS_CC); } + | T_GLOBAL global_var_list ';' + | T_STATIC static_var_list ';' + | T_ECHO echo_expr_list ';' + | T_INLINE_HTML { zend_do_echo(&$1 TSRMLS_CC); } + | expr ';' { zend_do_free(&$1 TSRMLS_CC); } + | T_UNSET '(' unset_variables ')' ';' + | T_FOREACH '(' variable T_AS + { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 1 TSRMLS_CC); } + foreach_variable foreach_optional_arg ')' { zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); } + foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); } + | T_FOREACH '(' expr_without_variable T_AS + { zend_do_foreach_begin(&$1, &$2, &$3, &$4, 0 TSRMLS_CC); } + variable foreach_optional_arg ')' { zend_check_writable_variable(&$6); zend_do_foreach_cont(&$1, &$2, &$4, &$6, &$7 TSRMLS_CC); } + foreach_statement { zend_do_foreach_end(&$1, &$4 TSRMLS_CC); } + | T_DECLARE { $1.u.op.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); } + | ';' /* empty statement */ + | T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}' + T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); } + fully_qualified_class_name { zend_do_first_catch(&$7 TSRMLS_CC); } + T_VARIABLE ')' { zend_do_begin_catch(&$1, &$9, &$11, &$7 TSRMLS_CC); } + '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } + additional_catches { zend_do_mark_last_catch(&$7, &$18 TSRMLS_CC); } + | T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); } + | T_GOTO T_STRING ';' { zend_do_goto(&$2 TSRMLS_CC); } +; + + +additional_catches: + non_empty_additional_catches { $$ = $1; } + | /* empty */ { $$.u.op.opline_num = -1; } +; + +non_empty_additional_catches: + additional_catch { $$ = $1; } + | non_empty_additional_catches additional_catch { $$ = $2; } +; + + +additional_catch: + T_CATCH '(' fully_qualified_class_name { $$.u.op.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); } +; + + +unset_variables: + unset_variable + | unset_variables ',' unset_variable +; + +unset_variable: + variable { zend_do_end_variable_parse(&$1, BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1 TSRMLS_CC); } +; + +function_declaration_statement: + unticked_function_declaration_statement { DO_TICKS(); } +; + +class_declaration_statement: + unticked_class_declaration_statement { DO_TICKS(); } +; + + +is_reference: + /* empty */ { $$.op_type = ZEND_RETURN_VAL; } + | '&' { $$.op_type = ZEND_RETURN_REF; } +; + + +unticked_function_declaration_statement: + function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); } + '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); } +; + +unticked_class_declaration_statement: + class_entry_type T_STRING extends_from + { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } + implements_list + '{' + class_statement_list + '}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); } + | interface_entry T_STRING + { zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); } + interface_extends_list + '{' + class_statement_list + '}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); } +; + + +class_entry_type: + T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = 0; } + | T_ABSTRACT T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } + | T_TRAIT { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_TRAIT; } + | T_FINAL T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_FINAL_CLASS; } +; + +extends_from: + /* empty */ { $$.op_type = IS_UNUSED; } + | T_EXTENDS fully_qualified_class_name { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); } +; + +interface_entry: + T_INTERFACE { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_INTERFACE; } +; + +interface_extends_list: + /* empty */ + | T_EXTENDS interface_list +; + +implements_list: + /* empty */ + | T_IMPLEMENTS interface_list +; + +interface_list: + fully_qualified_class_name { zend_do_implements_interface(&$1 TSRMLS_CC); } + | interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); } +; + +foreach_optional_arg: + /* empty */ { $$.op_type = IS_UNUSED; } + | T_DOUBLE_ARROW foreach_variable { $$ = $2; } +; + + +foreach_variable: + variable { zend_check_writable_variable(&$1); $$ = $1; } + | '&' variable { zend_check_writable_variable(&$2); $$ = $2; $$.EA |= ZEND_PARSED_REFERENCE_VARIABLE; } +; + +for_statement: + statement + | ':' inner_statement_list T_ENDFOR ';' +; + + +foreach_statement: + statement + | ':' inner_statement_list T_ENDFOREACH ';' +; + + +declare_statement: + statement + | ':' inner_statement_list T_ENDDECLARE ';' +; + + +declare_list: + T_STRING '=' static_scalar { zend_do_declare_stmt(&$1, &$3 TSRMLS_CC); } + | declare_list ',' T_STRING '=' static_scalar { zend_do_declare_stmt(&$3, &$5 TSRMLS_CC); } +; + + +switch_case_list: + '{' case_list '}' { $$ = $2; } + | '{' ';' case_list '}' { $$ = $3; } + | ':' case_list T_ENDSWITCH ';' { $$ = $2; } + | ':' ';' case_list T_ENDSWITCH ';' { $$ = $3; } +; + + +case_list: + /* empty */ { $$.op_type = IS_UNUSED; } + | case_list T_CASE expr case_separator { zend_do_extended_info(TSRMLS_C); zend_do_case_before_statement(&$1, &$2, &$3 TSRMLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 TSRMLS_CC); $$.op_type = IS_CONST; } + | case_list T_DEFAULT case_separator { zend_do_extended_info(TSRMLS_C); zend_do_default_before_statement(&$1, &$2 TSRMLS_CC); } inner_statement_list { zend_do_case_after_statement(&$$, &$2 TSRMLS_CC); $$.op_type = IS_CONST; } +; + + +case_separator: + ':' + | ';' +; + + +while_statement: + statement + | ':' inner_statement_list T_ENDWHILE ';' +; + + + +elseif_list: + /* empty */ + | elseif_list T_ELSEIF '(' expr ')' { zend_do_if_cond(&$4, &$5 TSRMLS_CC); } statement { zend_do_if_after_statement(&$5, 0 TSRMLS_CC); } +; + + +new_elseif_list: + /* empty */ + | new_elseif_list T_ELSEIF '(' expr ')' ':' { zend_do_if_cond(&$4, &$5 TSRMLS_CC); } inner_statement_list { zend_do_if_after_statement(&$5, 0 TSRMLS_CC); } +; + + +else_single: + /* empty */ + | T_ELSE statement +; + + +new_else_single: + /* empty */ + | T_ELSE ':' inner_statement_list +; + + +parameter_list: + non_empty_parameter_list + | /* empty */ +; + + +non_empty_parameter_list: + optional_class_type T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$2, &$$, NULL, &$1, 0 TSRMLS_CC); } + | optional_class_type '&' T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$3, &$$, NULL, &$1, 1 TSRMLS_CC); } + | optional_class_type '&' T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$3, &$$, &$5, &$1, 1 TSRMLS_CC); } + | optional_class_type T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$2, &$$, &$4, &$1, 0 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type T_VARIABLE { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$4, &$$, NULL, &$3, 0 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$5, &$$, NULL, &$3, 1 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$5, &$$, &$7, &$3, 1 TSRMLS_CC); } + | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$4, &$$, &$6, &$3, 0 TSRMLS_CC); } +; + + +optional_class_type: + /* empty */ { $$.op_type = IS_UNUSED; } + | T_ARRAY { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_ARRAY; } + | T_CALLABLE { $$.op_type = IS_CONST; Z_TYPE($$.u.constant)=IS_CALLABLE; } + | fully_qualified_class_name { $$ = $1; } +; + + +function_call_parameter_list: + non_empty_function_call_parameter_list { $$ = $1; } + | /* empty */ { Z_LVAL($$.u.constant) = 0; } +; + + +non_empty_function_call_parameter_list: + expr_without_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } + | variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } + | '&' w_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } + | non_empty_function_call_parameter_list ',' expr_without_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } + | non_empty_function_call_parameter_list ',' variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } + | non_empty_function_call_parameter_list ',' '&' w_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$4, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } +; + +global_var_list: + global_var_list ',' global_var { zend_do_fetch_global_variable(&$3, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); } + | global_var { zend_do_fetch_global_variable(&$1, NULL, ZEND_FETCH_GLOBAL_LOCK TSRMLS_CC); } +; + + +global_var: + T_VARIABLE { $$ = $1; } + | '$' r_variable { $$ = $2; } + | '$' '{' expr '}' { $$ = $3; } +; + + +static_var_list: + static_var_list ',' T_VARIABLE { zend_do_fetch_static_variable(&$3, NULL, ZEND_FETCH_STATIC TSRMLS_CC); } + | static_var_list ',' T_VARIABLE '=' static_scalar { zend_do_fetch_static_variable(&$3, &$5, ZEND_FETCH_STATIC TSRMLS_CC); } + | T_VARIABLE { zend_do_fetch_static_variable(&$1, NULL, ZEND_FETCH_STATIC TSRMLS_CC); } + | T_VARIABLE '=' static_scalar { zend_do_fetch_static_variable(&$1, &$3, ZEND_FETCH_STATIC TSRMLS_CC); } + +; + + +class_statement_list: + class_statement_list class_statement + | /* empty */ +; + + +class_statement: + variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';' + | class_constant_declaration ';' + | trait_use_statement + | method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } '(' + parameter_list ')' method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); } +; + +trait_use_statement: + T_USE trait_list trait_adaptations +; + +trait_list: + fully_qualified_class_name { zend_do_implements_trait(&$1 TSRMLS_CC); } + | trait_list ',' fully_qualified_class_name { zend_do_implements_trait(&$3 TSRMLS_CC); } +; + +trait_adaptations: + ';' + | '{' trait_adaptation_list '}' +; + +trait_adaptation_list: + /* empty */ + | non_empty_trait_adaptation_list +; + +non_empty_trait_adaptation_list: + trait_adaptation_statement + | non_empty_trait_adaptation_list trait_adaptation_statement +; + +trait_adaptation_statement: + trait_precedence ';' { zend_add_trait_precedence(&$1 TSRMLS_CC); } + | trait_alias ';' { zend_add_trait_alias(&$1 TSRMLS_CC); } +; + +trait_precedence: + trait_method_reference_fully_qualified T_INSTEADOF trait_reference_list { zend_prepare_trait_precedence(&$$, &$1, &$3 TSRMLS_CC); } +; + +trait_reference_list: + fully_qualified_class_name { zend_resolve_class_name(&$1, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); zend_init_list(&$$.u.op.ptr, Z_STRVAL($1.u.constant) TSRMLS_CC); } + | trait_reference_list ',' fully_qualified_class_name { zend_resolve_class_name(&$3, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC); zend_add_to_list(&$1.u.op.ptr, Z_STRVAL($3.u.constant) TSRMLS_CC); $$ = $1; } +; + +trait_method_reference: + T_STRING { zend_prepare_reference(&$$, NULL, &$1 TSRMLS_CC); } + | trait_method_reference_fully_qualified { $$ = $1; } +; + +trait_method_reference_fully_qualified: + fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_prepare_reference(&$$, &$1, &$3 TSRMLS_CC); } +; + +trait_alias: + trait_method_reference T_AS trait_modifiers T_STRING { zend_prepare_trait_alias(&$$, &$1, &$3, &$4 TSRMLS_CC); } + | trait_method_reference T_AS member_modifier { zend_prepare_trait_alias(&$$, &$1, &$3, NULL TSRMLS_CC); } +; + +trait_modifiers: + /* empty */ { Z_LVAL($$.u.constant) = 0x0; } /* No change of methods visibility */ + | member_modifier { $$ = $1; } /* REM: Keep in mind, there are not only visibility modifiers */ +; + +method_body: + ';' /* abstract method */ { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; } + | '{' inner_statement_list '}' { Z_LVAL($$.u.constant) = 0; } +; + +variable_modifiers: + non_empty_member_modifiers { $$ = $1; } + | T_VAR { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; } +; + +method_modifiers: + /* empty */ { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; } + | non_empty_member_modifiers { $$ = $1; if (!(Z_LVAL($$.u.constant) & ZEND_ACC_PPP_MASK)) { Z_LVAL($$.u.constant) |= ZEND_ACC_PUBLIC; } } +; + +non_empty_member_modifiers: + member_modifier { $$ = $1; } + | non_empty_member_modifiers member_modifier { Z_LVAL($$.u.constant) = zend_do_verify_access_types(&$1, &$2); } +; + +member_modifier: + T_PUBLIC { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; } + | T_PROTECTED { Z_LVAL($$.u.constant) = ZEND_ACC_PROTECTED; } + | T_PRIVATE { Z_LVAL($$.u.constant) = ZEND_ACC_PRIVATE; } + | T_STATIC { Z_LVAL($$.u.constant) = ZEND_ACC_STATIC; } + | T_ABSTRACT { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; } + | T_FINAL { Z_LVAL($$.u.constant) = ZEND_ACC_FINAL; } +; + +class_variable_declaration: + class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$3, NULL, CG(access_type) TSRMLS_CC); } + | class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); } + | T_VARIABLE { zend_do_declare_property(&$1, NULL, CG(access_type) TSRMLS_CC); } + | T_VARIABLE '=' static_scalar { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); } +; + +class_constant_declaration: + class_constant_declaration ',' T_STRING '=' static_scalar { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); } +; + +echo_expr_list: + echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); } + | expr { zend_do_echo(&$1 TSRMLS_CC); } +; + + +for_expr: + /* empty */ { $$.op_type = IS_CONST; Z_TYPE($$.u.constant) = IS_BOOL; Z_LVAL($$.u.constant) = 1; } + | non_empty_for_expr { $$ = $1; } +; + +non_empty_for_expr: + non_empty_for_expr ',' { zend_do_free(&$1 TSRMLS_CC); } expr { $$ = $4; } + | expr { $$ = $1; } +; + +chaining_method_or_property: + chaining_method_or_property variable_property { $$.EA = $2.EA; } + | variable_property { $$.EA = $1.EA; } +; + +chaining_dereference: + chaining_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | '[' dim_offset ']' { zend_do_pop_object(&$1 TSRMLS_CC); fetch_array_dim(&$$, &$1, &$2 TSRMLS_CC); } +; + +chaining_instance_call: + chaining_dereference { zend_do_push_object(&$1 TSRMLS_CC); } chaining_method_or_property { $$ = $3; } + | chaining_dereference { zend_do_push_object(&$1 TSRMLS_CC); $$ = $1; } + | chaining_method_or_property { $$ = $1; } +; + +instance_call: + /* empty */ { $$ = $0; } + | { zend_do_push_object(&$0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); } + chaining_instance_call { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); } +; + +new_expr: + T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} +; + +expr_without_variable: + T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } + | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } + | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } + | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } + | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } + | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_MINUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_MUL_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_DIV_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_CONCAT_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_MOD_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_AND_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_OR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_XOR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_SL_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SL, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_SR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SR, &$$, &$1, &$3 TSRMLS_CC); } + | rw_variable T_INC { zend_do_post_incdec(&$$, &$1, ZEND_POST_INC TSRMLS_CC); } + | T_INC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_INC TSRMLS_CC); } + | rw_variable T_DEC { zend_do_post_incdec(&$$, &$1, ZEND_POST_DEC TSRMLS_CC); } + | T_DEC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_DEC TSRMLS_CC); } + | expr T_BOOLEAN_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } + | expr T_BOOLEAN_AND { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } + | expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } + | expr T_LOGICAL_AND { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_and_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } + | expr T_LOGICAL_XOR expr { zend_do_binary_op(ZEND_BOOL_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | expr '|' expr { zend_do_binary_op(ZEND_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | expr '&' expr { zend_do_binary_op(ZEND_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | expr '^' expr { zend_do_binary_op(ZEND_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | expr '.' expr { zend_do_binary_op(ZEND_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | expr '+' expr { zend_do_binary_op(ZEND_ADD, &$$, &$1, &$3 TSRMLS_CC); } + | expr '-' expr { zend_do_binary_op(ZEND_SUB, &$$, &$1, &$3 TSRMLS_CC); } + | expr '*' expr { zend_do_binary_op(ZEND_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | expr '/' expr { zend_do_binary_op(ZEND_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | expr '%' expr { zend_do_binary_op(ZEND_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | expr T_SL expr { zend_do_binary_op(ZEND_SL, &$$, &$1, &$3 TSRMLS_CC); } + | expr T_SR expr { zend_do_binary_op(ZEND_SR, &$$, &$1, &$3 TSRMLS_CC); } + | '+' expr %prec T_INC { ZVAL_LONG(&$1.u.constant, 0); if ($2.op_type == IS_CONST) { add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } else { $1.op_type = IS_CONST; INIT_PZVAL(&$1.u.constant); zend_do_binary_op(ZEND_ADD, &$$, &$1, &$2 TSRMLS_CC); } } + | '-' expr %prec T_INC { ZVAL_LONG(&$1.u.constant, 0); if ($2.op_type == IS_CONST) { sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } else { $1.op_type = IS_CONST; INIT_PZVAL(&$1.u.constant); zend_do_binary_op(ZEND_SUB, &$$, &$1, &$2 TSRMLS_CC); } } + | '!' expr { zend_do_unary_op(ZEND_BOOL_NOT, &$$, &$2 TSRMLS_CC); } + | '~' expr { zend_do_unary_op(ZEND_BW_NOT, &$$, &$2 TSRMLS_CC); } + | expr T_IS_IDENTICAL expr { zend_do_binary_op(ZEND_IS_IDENTICAL, &$$, &$1, &$3 TSRMLS_CC); } + | expr T_IS_NOT_IDENTICAL expr { zend_do_binary_op(ZEND_IS_NOT_IDENTICAL, &$$, &$1, &$3 TSRMLS_CC); } + | expr T_IS_EQUAL expr { zend_do_binary_op(ZEND_IS_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } + | expr T_IS_NOT_EQUAL expr { zend_do_binary_op(ZEND_IS_NOT_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } + | expr '<' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$1, &$3 TSRMLS_CC); } + | expr T_IS_SMALLER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$1, &$3 TSRMLS_CC); } + | expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); } + | expr T_IS_GREATER_OR_EQUAL expr { zend_do_binary_op(ZEND_IS_SMALLER_OR_EQUAL, &$$, &$3, &$1 TSRMLS_CC); } + | expr T_INSTANCEOF class_name_reference { zend_do_instanceof(&$$, &$1, &$3, 0 TSRMLS_CC); } + | '(' expr ')' { $$ = $2; } + | new_expr { $$ = $1; } + | '(' new_expr ')' { $$ = $2; } instance_call { $$ = $5; } + | expr '?' { zend_do_begin_qm_op(&$1, &$2 TSRMLS_CC); } + expr ':' { zend_do_qm_true(&$4, &$2, &$5 TSRMLS_CC); } + expr { zend_do_qm_false(&$$, &$7, &$2, &$5 TSRMLS_CC); } + | expr '?' ':' { zend_do_jmp_set(&$1, &$2, &$3 TSRMLS_CC); } + expr { zend_do_jmp_set_else(&$$, &$5, &$2, &$3 TSRMLS_CC); } + | internal_functions_in_yacc { $$ = $1; } + | T_INT_CAST expr { zend_do_cast(&$$, &$2, IS_LONG TSRMLS_CC); } + | T_DOUBLE_CAST expr { zend_do_cast(&$$, &$2, IS_DOUBLE TSRMLS_CC); } + | T_STRING_CAST expr { zend_do_cast(&$$, &$2, IS_STRING TSRMLS_CC); } + | T_ARRAY_CAST expr { zend_do_cast(&$$, &$2, IS_ARRAY TSRMLS_CC); } + | T_OBJECT_CAST expr { zend_do_cast(&$$, &$2, IS_OBJECT TSRMLS_CC); } + | T_BOOL_CAST expr { zend_do_cast(&$$, &$2, IS_BOOL TSRMLS_CC); } + | T_UNSET_CAST expr { zend_do_cast(&$$, &$2, IS_NULL TSRMLS_CC); } + | T_EXIT exit_expr { zend_do_exit(&$$, &$2 TSRMLS_CC); } + | '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } + | scalar { $$ = $1; } + | T_ARRAY '(' array_pair_list ')' { $$ = $3; } + | '[' array_pair_list ']' { $$ = $2; } + | '`' backticks_expr '`' { zend_do_shell_exec(&$$, &$2 TSRMLS_CC); } + | T_PRINT expr { zend_do_print(&$$, &$2 TSRMLS_CC); } + | function is_reference '(' { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); } + parameter_list ')' lexical_vars '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $4; } + | T_STATIC function is_reference '(' { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); } + parameter_list ')' lexical_vars '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $5; } +; + +function: + T_FUNCTION { $$.u.op.opline_num = CG(zend_lineno); } +; + +lexical_vars: + /* empty */ + | T_USE '(' lexical_var_list ')' +; + +lexical_var_list: + lexical_var_list ',' T_VARIABLE { zend_do_fetch_lexical_variable(&$3, 0 TSRMLS_CC); } + | lexical_var_list ',' '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$4, 1 TSRMLS_CC); } + | T_VARIABLE { zend_do_fetch_lexical_variable(&$1, 0 TSRMLS_CC); } + | '&' T_VARIABLE { zend_do_fetch_lexical_variable(&$2, 1 TSRMLS_CC); } +; + +function_call: + namespace_name '(' { $2.u.op.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(&$1, &$$, &$4, 0, $2.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | T_NAMESPACE T_NS_SEPARATOR namespace_name '(' { $1.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$1.u.constant); zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC); $4.u.op.opline_num = zend_do_begin_function_call(&$1, 0 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(&$1, &$$, &$6, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | T_NS_SEPARATOR namespace_name '(' { $3.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(&$2, &$$, &$5, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name '(' { $4.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, &$6, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name '(' { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + function_call_parameter_list + ')' { zend_do_end_function_call(NULL, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + | variable_without_objects '(' { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } + function_call_parameter_list ')' + { zend_do_end_function_call(&$1, &$$, &$4, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} +; + +class_name: + T_STATIC { $$.op_type = IS_CONST; ZVAL_STRINGL(&$$.u.constant, "static", sizeof("static")-1, 1);} + | namespace_name { $$ = $1; } + | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); $$ = $2; } +; + +fully_qualified_class_name: + namespace_name { $$ = $1; } + | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); $$ = $2; } +; + + + +class_name_reference: + class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | dynamic_class_name_reference { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } +; + + +dynamic_class_name_reference: + base_variable T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } + object_property { zend_do_push_object(&$4 TSRMLS_CC); } dynamic_class_name_variable_properties + { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = ZEND_PARSED_MEMBER; } + | base_variable { $$ = $1; } +; + + +dynamic_class_name_variable_properties: + dynamic_class_name_variable_properties dynamic_class_name_variable_property + | /* empty */ +; + + +dynamic_class_name_variable_property: + T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } +; + +exit_expr: + /* empty */ { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; } + | '(' ')' { memset(&$$, 0, sizeof(znode)); $$.op_type = IS_UNUSED; } + | '(' expr ')' { $$ = $2; } +; + +backticks_expr: + /* empty */ { ZVAL_EMPTY_STRING(&$$.u.constant); INIT_PZVAL(&$$.u.constant); $$.op_type = IS_CONST; } + | T_ENCAPSED_AND_WHITESPACE { $$ = $1; } + | encaps_list { $$ = $1; } +; + + +ctor_arguments: + /* empty */ { Z_LVAL($$.u.constant)=0; } + | '(' function_call_parameter_list ')' { $$ = $2; } +; + + +common_scalar: + T_LNUMBER { $$ = $1; } + | T_DNUMBER { $$ = $1; } + | T_CONSTANT_ENCAPSED_STRING { $$ = $1; } + | T_LINE { $$ = $1; } + | T_FILE { $$ = $1; } + | T_DIR { $$ = $1; } + | T_TRAIT_C { $$ = $1; } + | T_METHOD_C { $$ = $1; } + | T_FUNC_C { $$ = $1; } + | T_NS_C { $$ = $1; } + | T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$ = $2; CG(heredoc) = Z_STRVAL($1.u.constant); CG(heredoc_len) = Z_STRLEN($1.u.constant); } + | T_START_HEREDOC T_END_HEREDOC { ZVAL_EMPTY_STRING(&$$.u.constant); INIT_PZVAL(&$$.u.constant); $$.op_type = IS_CONST; CG(heredoc) = Z_STRVAL($1.u.constant); CG(heredoc_len) = Z_STRLEN($1.u.constant); } +; + + +static_scalar: /* compile-time evaluated scalars */ + common_scalar { $$ = $1; } + | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); } + | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); } + | '+' static_scalar { ZVAL_LONG(&$1.u.constant, 0); add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } + | '-' static_scalar { ZVAL_LONG(&$1.u.constant, 0); sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; } + | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } + | '[' static_array_pair_list ']' { $$ = $2; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; } + | static_class_constant { $$ = $1; } + | T_CLASS_C { $$ = $1; } +; + +static_class_constant: + class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_CT, 0 TSRMLS_CC); } +; + +scalar: + T_STRING_VARNAME { $$ = $1; } + | class_constant { $$ = $1; } + | namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); } + | T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_RT, 0 TSRMLS_CC); } + | T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_RT, 0 TSRMLS_CC); } + | common_scalar { $$ = $1; } + | '"' encaps_list '"' { $$ = $2; } + | T_START_HEREDOC encaps_list T_END_HEREDOC { $$ = $2; CG(heredoc) = Z_STRVAL($1.u.constant); CG(heredoc_len) = Z_STRLEN($1.u.constant); } + | T_CLASS_C { if (Z_TYPE($1.u.constant) == IS_CONSTANT) {zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC);} else {$$ = $1;} } +; + + +static_array_pair_list: + /* empty */ { $$.op_type = IS_CONST; INIT_PZVAL(&$$.u.constant); array_init(&$$.u.constant); } + | non_empty_static_array_pair_list possible_comma { $$ = $1; } +; + +possible_comma: + /* empty */ + | ',' +; + +non_empty_static_array_pair_list: + non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW static_scalar { zend_do_add_static_array_element(&$$, &$3, &$5); } + | non_empty_static_array_pair_list ',' static_scalar { zend_do_add_static_array_element(&$$, NULL, &$3); } + | static_scalar T_DOUBLE_ARROW static_scalar { $$.op_type = IS_CONST; INIT_PZVAL(&$$.u.constant); array_init(&$$.u.constant); zend_do_add_static_array_element(&$$, &$1, &$3); } + | static_scalar { $$.op_type = IS_CONST; INIT_PZVAL(&$$.u.constant); array_init(&$$.u.constant); zend_do_add_static_array_element(&$$, NULL, &$1); } +; + +expr: + r_variable { $$ = $1; } + | expr_without_variable { $$ = $1; } +; + + +r_variable: + variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } +; + + +w_variable: + variable { zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $$ = $1; + zend_check_writable_variable(&$1); } +; + +rw_variable: + variable { zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); $$ = $1; + zend_check_writable_variable(&$1); } +; + +variable: + base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); } + object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties + { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $1.EA | ($7.EA ? $7.EA : $6.EA); } + | base_variable_with_function_calls { $$ = $1; } +; + +variable_properties: + variable_properties variable_property { $$.EA = $2.EA; } + | /* empty */ { $$.EA = 0; } +; + + +variable_property: + T_OBJECT_OPERATOR object_property { zend_do_push_object(&$2 TSRMLS_CC); } method_or_not { $$.EA = $4.EA; } +; + +array_method_dereference: + array_method_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | method '[' dim_offset ']' { $1.EA = ZEND_PARSED_METHOD_CALL; fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } +; + +method: + '(' { zend_do_pop_object(&$1 TSRMLS_CC); zend_do_begin_method_call(&$1 TSRMLS_CC); } + function_call_parameter_list ')' + { zend_do_end_function_call(&$1, &$$, &$3, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } +; + +method_or_not: + method { $$ = $1; $$.EA = ZEND_PARSED_METHOD_CALL; zend_do_push_object(&$$ TSRMLS_CC); } + | array_method_dereference { $$ = $1; zend_do_push_object(&$$ TSRMLS_CC); } + | /* empty */ { $$.EA = ZEND_PARSED_MEMBER; } +; + +variable_without_objects: + reference_variable { $$ = $1; } + | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); } +; + +static_member: + class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 TSRMLS_CC); } + +; + +variable_class_name: + reference_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } +; + +array_function_dereference: + array_function_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | function_call { zend_do_begin_variable_parse(TSRMLS_C); $1.EA = ZEND_PARSED_FUNCTION_CALL; } + '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); } +; + +base_variable_with_function_calls: + base_variable { $$ = $1; } + | array_function_dereference { $$ = $1; } + | function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; } +; + + +base_variable: + reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; } + | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; } + | static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; } +; + +reference_variable: + reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } + | compound_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } +; + + +compound_variable: + T_VARIABLE { $$ = $1; } + | '$' '{' expr '}' { $$ = $3; } +; + +dim_offset: + /* empty */ { $$.op_type = IS_UNUSED; } + | expr { $$ = $1; } +; + + +object_property: + object_dim_list { $$ = $1; } + | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); } { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} +; + +object_dim_list: + object_dim_list '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); } + | object_dim_list '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); } + | variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} +; + +variable_name: + T_STRING { $$ = $1; } + | '{' expr '}' { $$ = $2; } +; + +simple_indirect_reference: + '$' { Z_LVAL($$.u.constant) = 1; } + | simple_indirect_reference '$' { Z_LVAL($$.u.constant)++; } +; + +assignment_list: + assignment_list ',' assignment_list_element + | assignment_list_element +; + + +assignment_list_element: + variable { zend_do_add_list_element(&$1 TSRMLS_CC); } + | T_LIST '(' { zend_do_new_list_begin(TSRMLS_C); } assignment_list ')' { zend_do_new_list_end(TSRMLS_C); } + | /* empty */ { zend_do_add_list_element(NULL TSRMLS_CC); } +; + + +array_pair_list: + /* empty */ { zend_do_init_array(&$$, NULL, NULL, 0 TSRMLS_CC); } + | non_empty_array_pair_list possible_comma { $$ = $1; } +; + +non_empty_array_pair_list: + non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr { zend_do_add_array_element(&$$, &$5, &$3, 0 TSRMLS_CC); } + | non_empty_array_pair_list ',' expr { zend_do_add_array_element(&$$, &$3, NULL, 0 TSRMLS_CC); } + | expr T_DOUBLE_ARROW expr { zend_do_init_array(&$$, &$3, &$1, 0 TSRMLS_CC); } + | expr { zend_do_init_array(&$$, &$1, NULL, 0 TSRMLS_CC); } + | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable { zend_do_add_array_element(&$$, &$6, &$3, 1 TSRMLS_CC); } + | non_empty_array_pair_list ',' '&' w_variable { zend_do_add_array_element(&$$, &$4, NULL, 1 TSRMLS_CC); } + | expr T_DOUBLE_ARROW '&' w_variable { zend_do_init_array(&$$, &$4, &$1, 1 TSRMLS_CC); } + | '&' w_variable { zend_do_init_array(&$$, &$2, NULL, 1 TSRMLS_CC); } +; + +encaps_list: + encaps_list encaps_var { zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); zend_do_add_variable(&$$, &$1, &$2 TSRMLS_CC); } + | encaps_list T_ENCAPSED_AND_WHITESPACE { zend_do_add_string(&$$, &$1, &$2 TSRMLS_CC); } + | encaps_var { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_add_variable(&$$, NULL, &$1 TSRMLS_CC); } + | T_ENCAPSED_AND_WHITESPACE encaps_var { zend_do_add_string(&$$, NULL, &$1 TSRMLS_CC); zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); zend_do_add_variable(&$$, &$$, &$2 TSRMLS_CC); } +; + + + +encaps_var: + T_VARIABLE { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } + | T_VARIABLE '[' { zend_do_begin_variable_parse(TSRMLS_C); } encaps_var_offset ']' { fetch_array_begin(&$$, &$1, &$4 TSRMLS_CC); } + | T_VARIABLE T_OBJECT_OPERATOR T_STRING { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$2, &$1, 1 TSRMLS_CC); zend_do_fetch_property(&$$, &$2, &$3 TSRMLS_CC); } + | T_DOLLAR_OPEN_CURLY_BRACES expr '}' { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$2, 1 TSRMLS_CC); } + | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}' { zend_do_begin_variable_parse(TSRMLS_C); fetch_array_begin(&$$, &$2, &$4 TSRMLS_CC); } + | T_CURLY_OPEN variable '}' { $$ = $2; } +; + + +encaps_var_offset: + T_STRING { $$ = $1; } + | T_NUM_STRING { $$ = $1; } + | T_VARIABLE { fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); } +; + + +internal_functions_in_yacc: + T_ISSET '(' isset_variables ')' { $$ = $3; } + | T_EMPTY '(' variable ')' { zend_do_isset_or_isempty(ZEND_ISEMPTY, &$$, &$3 TSRMLS_CC); } + | T_INCLUDE expr { zend_do_include_or_eval(ZEND_INCLUDE, &$$, &$2 TSRMLS_CC); } + | T_INCLUDE_ONCE expr { zend_do_include_or_eval(ZEND_INCLUDE_ONCE, &$$, &$2 TSRMLS_CC); } + | T_EVAL '(' expr ')' { zend_do_include_or_eval(ZEND_EVAL, &$$, &$3 TSRMLS_CC); } + | T_REQUIRE expr { zend_do_include_or_eval(ZEND_REQUIRE, &$$, &$2 TSRMLS_CC); } + | T_REQUIRE_ONCE expr { zend_do_include_or_eval(ZEND_REQUIRE_ONCE, &$$, &$2 TSRMLS_CC); } +; + +isset_variables: + variable { zend_do_isset_or_isempty(ZEND_ISSET, &$$, &$1 TSRMLS_CC); } + | isset_variables ',' { zend_do_boolean_and_begin(&$1, &$2 TSRMLS_CC); } variable { znode tmp; zend_do_isset_or_isempty(ZEND_ISSET, &tmp, &$4 TSRMLS_CC); zend_do_boolean_and_end(&$$, &$1, &tmp, &$2 TSRMLS_CC); } +; + +class_constant: + class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); } + | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); } +; + +%% + +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T zend_yytnamerr(char *yyres, const char *yystr) +{ + if (!yyres) { + return yystrlen(yystr); + } + { + TSRMLS_FETCH(); + if (CG(parse_error) == 0) { + char buffer[120]; + const unsigned char *end, *str, *tok1 = NULL, *tok2 = NULL; + unsigned int len = 0, toklen = 0, yystr_len; + + CG(parse_error) = 1; + + if (LANG_SCNG(yy_text)[0] == 0 && + LANG_SCNG(yy_leng) == 1 && + memcmp(yystr, ZEND_STRL("\"end of file\"")) == 0) { + yystpcpy(yyres, "end of file"); + return sizeof("end of file")-1; + } + + str = LANG_SCNG(yy_text); + end = memchr(str, '\n', LANG_SCNG(yy_leng)); + yystr_len = yystrlen(yystr); + + if ((tok1 = memchr(yystr, '(', yystr_len)) != NULL + && (tok2 = zend_memrchr(yystr, ')', yystr_len)) != NULL) { + toklen = (tok2 - tok1) + 1; + } else { + tok1 = tok2 = NULL; + toklen = 0; + } + + if (end == NULL) { + len = LANG_SCNG(yy_leng) > 30 ? 30 : LANG_SCNG(yy_leng); + } else { + len = (end - str) > 30 ? 30 : (end - str); + } + if (toklen) { + snprintf(buffer, sizeof(buffer), "'%.*s' %.*s", len, str, toklen, tok1); + } else { + snprintf(buffer, sizeof(buffer), "'%.*s'", len, str); + } + yystpcpy(yyres, buffer); + return len + (toklen ? toklen + 1 : 0) + 2; + } + } + if (*yystr == '"') { + YYSIZE_T yyn = 0; + const char *yyp = yystr; + + for (; *++yyp != '"'; ++yyn) { + yyres[yyn] = *yyp; + } + yyres[yyn] = '\0'; + return yyn; + } + yystpcpy(yyres, yystr); + return strlen(yystr); +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + */ diff --git a/recherches/grammaire/zend_language_scanner.l b/recherches/grammaire/zend_language_scanner.l new file mode 100644 index 0000000..d530b53 --- /dev/null +++ b/recherches/grammaire/zend_language_scanner.l @@ -0,0 +1,2414 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Marcus Boerger <helly@php.net> | + | Nuno Lopes <nlopess@php.net> | + | Scott MacVicar <scottmac@php.net> | + | Flex version authors: | + | Andi Gutmans <andi@zend.com> | + | Zeev Suraski <zeev@zend.com> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#if 0 +# define YYDEBUG(s, c) printf("state: %d char: %c\n", s, c) +#else +# define YYDEBUG(s, c) +#endif + +#include "zend_language_scanner_defs.h" + +#include <errno.h> +#include "zend.h" +#include "zend_alloc.h" +#include <zend_language_parser.h> +#include "zend_compile.h" +#include "zend_language_scanner.h" +#include "zend_highlight.h" +#include "zend_constants.h" +#include "zend_variables.h" +#include "zend_operators.h" +#include "zend_API.h" +#include "zend_strtod.h" +#include "zend_exceptions.h" +#include "tsrm_virtual_cwd.h" +#include "tsrm_config_common.h" + +#define YYCTYPE unsigned char +#define YYFILL(n) { if ((YYCURSOR + n) >= (YYLIMIT + ZEND_MMAP_AHEAD)) { return 0; } } +#define YYCURSOR SCNG(yy_cursor) +#define YYLIMIT SCNG(yy_limit) +#define YYMARKER SCNG(yy_marker) + +#define YYGETCONDITION() SCNG(yy_state) +#define YYSETCONDITION(s) SCNG(yy_state) = s + +#define STATE(name) yyc##name + +/* emulate flex constructs */ +#define BEGIN(state) YYSETCONDITION(STATE(state)) +#define YYSTATE YYGETCONDITION() +#define yytext ((char*)SCNG(yy_text)) +#define yyleng SCNG(yy_leng) +#define yyless(x) do { YYCURSOR = (unsigned char*)yytext + x; \ + yyleng = (unsigned int)x; } while(0) +#define yymore() goto yymore_restart + +/* perform sanity check. If this message is triggered you should + increase the ZEND_MMAP_AHEAD value in the zend_streams.h file */ +/*!max:re2c */ +#if ZEND_MMAP_AHEAD < YYMAXFILL +# error ZEND_MMAP_AHEAD should be greater than or equal to YYMAXFILL +#endif + +#ifdef HAVE_STDARG_H +# include <stdarg.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +/* Globals Macros */ +#define SCNG LANG_SCNG +#ifdef ZTS +ZEND_API ts_rsrc_id language_scanner_globals_id; +#else +ZEND_API zend_php_scanner_globals language_scanner_globals; +#endif + +#define HANDLE_NEWLINES(s, l) \ +do { \ + char *p = (s), *boundary = p+(l); \ + \ + while (p<boundary) { \ + if (*p == '\n' || (*p == '\r' && (*(p+1) != '\n'))) { \ + CG(zend_lineno)++; \ + } \ + p++; \ + } \ +} while (0) + +#define HANDLE_NEWLINE(c) \ +{ \ + if (c == '\n' || c == '\r') { \ + CG(zend_lineno)++; \ + } \ +} + +/* To save initial string length after scanning to first variable, CG(doc_comment_len) can be reused */ +#define SET_DOUBLE_QUOTES_SCANNED_LENGTH(len) CG(doc_comment_len) = (len) +#define GET_DOUBLE_QUOTES_SCANNED_LENGTH() CG(doc_comment_len) + +#define IS_LABEL_START(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || (c) == '_' || (c) >= 0x7F) + +#define ZEND_IS_OCT(c) ((c)>='0' && (c)<='7') +#define ZEND_IS_HEX(c) (((c)>='0' && (c)<='9') || ((c)>='a' && (c)<='f') || ((c)>='A' && (c)<='F')) + +BEGIN_EXTERN_C() + +static size_t encoding_filter_script_to_internal(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC) +{ + const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C); + assert(internal_encoding && zend_multibyte_check_lexer_compatibility(internal_encoding)); + return zend_multibyte_encoding_converter(to, to_length, from, from_length, internal_encoding, LANG_SCNG(script_encoding) TSRMLS_CC); +} + +static size_t encoding_filter_script_to_intermediate(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC) +{ + return zend_multibyte_encoding_converter(to, to_length, from, from_length, zend_multibyte_encoding_utf8, LANG_SCNG(script_encoding) TSRMLS_CC); +} + +static size_t encoding_filter_intermediate_to_script(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC) +{ + return zend_multibyte_encoding_converter(to, to_length, from, from_length, +LANG_SCNG(script_encoding), zend_multibyte_encoding_utf8 TSRMLS_CC); +} + +static size_t encoding_filter_intermediate_to_internal(unsigned char **to, size_t *to_length, const unsigned char *from, size_t from_length TSRMLS_DC) +{ + const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C); + assert(internal_encoding && zend_multibyte_check_lexer_compatibility(internal_encoding)); + return zend_multibyte_encoding_converter(to, to_length, from, from_length, +internal_encoding, zend_multibyte_encoding_utf8 TSRMLS_CC); +} + + +static void _yy_push_state(int new_state TSRMLS_DC) +{ + zend_stack_push(&SCNG(state_stack), (void *) &YYGETCONDITION(), sizeof(int)); + YYSETCONDITION(new_state); +} + +#define yy_push_state(state_and_tsrm) _yy_push_state(yyc##state_and_tsrm) + +static void yy_pop_state(TSRMLS_D) +{ + int *stack_state; + zend_stack_top(&SCNG(state_stack), (void **) &stack_state); + YYSETCONDITION(*stack_state); + zend_stack_del_top(&SCNG(state_stack)); +} + +static void yy_scan_buffer(char *str, unsigned int len TSRMLS_DC) +{ + YYCURSOR = (YYCTYPE*)str; + YYLIMIT = YYCURSOR + len; + if (!SCNG(yy_start)) { + SCNG(yy_start) = YYCURSOR; + } +} + +void startup_scanner(TSRMLS_D) +{ + CG(parse_error) = 0; + CG(heredoc) = NULL; + CG(heredoc_len) = 0; + CG(doc_comment) = NULL; + CG(doc_comment_len) = 0; + zend_stack_init(&SCNG(state_stack)); +} + +void shutdown_scanner(TSRMLS_D) +{ + if (CG(heredoc)) { + efree(CG(heredoc)); + CG(heredoc_len)=0; + } + CG(parse_error) = 0; + zend_stack_destroy(&SCNG(state_stack)); + RESET_DOC_COMMENT(); +} + +ZEND_API void zend_save_lexical_state(zend_lex_state *lex_state TSRMLS_DC) +{ + lex_state->yy_leng = SCNG(yy_leng); + lex_state->yy_start = SCNG(yy_start); + lex_state->yy_text = SCNG(yy_text); + lex_state->yy_cursor = SCNG(yy_cursor); + lex_state->yy_marker = SCNG(yy_marker); + lex_state->yy_limit = SCNG(yy_limit); + + lex_state->state_stack = SCNG(state_stack); + zend_stack_init(&SCNG(state_stack)); + + lex_state->in = SCNG(yy_in); + lex_state->yy_state = YYSTATE; + lex_state->filename = zend_get_compiled_filename(TSRMLS_C); + lex_state->lineno = CG(zend_lineno); + + lex_state->script_org = SCNG(script_org); + lex_state->script_org_size = SCNG(script_org_size); + lex_state->script_filtered = SCNG(script_filtered); + lex_state->script_filtered_size = SCNG(script_filtered_size); + lex_state->input_filter = SCNG(input_filter); + lex_state->output_filter = SCNG(output_filter); + lex_state->script_encoding = SCNG(script_encoding); +} + +ZEND_API void zend_restore_lexical_state(zend_lex_state *lex_state TSRMLS_DC) +{ + SCNG(yy_leng) = lex_state->yy_leng; + SCNG(yy_start) = lex_state->yy_start; + SCNG(yy_text) = lex_state->yy_text; + SCNG(yy_cursor) = lex_state->yy_cursor; + SCNG(yy_marker) = lex_state->yy_marker; + SCNG(yy_limit) = lex_state->yy_limit; + + zend_stack_destroy(&SCNG(state_stack)); + SCNG(state_stack) = lex_state->state_stack; + + SCNG(yy_in) = lex_state->in; + YYSETCONDITION(lex_state->yy_state); + CG(zend_lineno) = lex_state->lineno; + zend_restore_compiled_filename(lex_state->filename TSRMLS_CC); + + if (SCNG(script_filtered)) { + efree(SCNG(script_filtered)); + SCNG(script_filtered) = NULL; + } + SCNG(script_org) = lex_state->script_org; + SCNG(script_org_size) = lex_state->script_org_size; + SCNG(script_filtered) = lex_state->script_filtered; + SCNG(script_filtered_size) = lex_state->script_filtered_size; + SCNG(input_filter) = lex_state->input_filter; + SCNG(output_filter) = lex_state->output_filter; + SCNG(script_encoding) = lex_state->script_encoding; + + if (CG(heredoc)) { + efree(CG(heredoc)); + CG(heredoc) = NULL; + CG(heredoc_len) = 0; + } +} + +ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle TSRMLS_DC) +{ + zend_llist_del_element(&CG(open_files), file_handle, (int (*)(void *, void *)) zend_compare_file_handles); + /* zend_file_handle_dtor() operates on the copy, so we have to NULLify the original here */ + file_handle->opened_path = NULL; + if (file_handle->free_filename) { + file_handle->filename = NULL; + } +} + +#define BOM_UTF32_BE "\x00\x00\xfe\xff" +#define BOM_UTF32_LE "\xff\xfe\x00\x00" +#define BOM_UTF16_BE "\xfe\xff" +#define BOM_UTF16_LE "\xff\xfe" +#define BOM_UTF8 "\xef\xbb\xbf" + +static const zend_encoding *zend_multibyte_detect_utf_encoding(const unsigned char *script, size_t script_size TSRMLS_DC) +{ + const unsigned char *p; + int wchar_size = 2; + int le = 0; + + /* utf-16 or utf-32? */ + p = script; + while ((p-script) < script_size) { + p = memchr(p, 0, script_size-(p-script)-2); + if (!p) { + break; + } + if (*(p+1) == '\0' && *(p+2) == '\0') { + wchar_size = 4; + break; + } + + /* searching for UTF-32 specific byte orders, so this will do */ + p += 4; + } + + /* BE or LE? */ + p = script; + while ((p-script) < script_size) { + if (*p == '\0' && *(p+wchar_size-1) != '\0') { + /* BE */ + le = 0; + break; + } else if (*p != '\0' && *(p+wchar_size-1) == '\0') { + /* LE* */ + le = 1; + break; + } + p += wchar_size; + } + + if (wchar_size == 2) { + return le ? zend_multibyte_encoding_utf16le : zend_multibyte_encoding_utf16be; + } else { + return le ? zend_multibyte_encoding_utf32le : zend_multibyte_encoding_utf32be; + } + + return NULL; +} + +static const zend_encoding* zend_multibyte_detect_unicode(TSRMLS_D) +{ + const zend_encoding *script_encoding = NULL; + int bom_size; + unsigned char *pos1, *pos2; + + if (LANG_SCNG(script_org_size) < sizeof(BOM_UTF32_LE)-1) { + return NULL; + } + + /* check out BOM */ + if (!memcmp(LANG_SCNG(script_org), BOM_UTF32_BE, sizeof(BOM_UTF32_BE)-1)) { + script_encoding = zend_multibyte_encoding_utf32be; + bom_size = sizeof(BOM_UTF32_BE)-1; + } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF32_LE, sizeof(BOM_UTF32_LE)-1)) { + script_encoding = zend_multibyte_encoding_utf32le; + bom_size = sizeof(BOM_UTF32_LE)-1; + } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF16_BE, sizeof(BOM_UTF16_BE)-1)) { + script_encoding = zend_multibyte_encoding_utf16be; + bom_size = sizeof(BOM_UTF16_BE)-1; + } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF16_LE, sizeof(BOM_UTF16_LE)-1)) { + script_encoding = zend_multibyte_encoding_utf16le; + bom_size = sizeof(BOM_UTF16_LE)-1; + } else if (!memcmp(LANG_SCNG(script_org), BOM_UTF8, sizeof(BOM_UTF8)-1)) { + script_encoding = zend_multibyte_encoding_utf8; + bom_size = sizeof(BOM_UTF8)-1; + } + + if (script_encoding) { + /* remove BOM */ + LANG_SCNG(script_org) += bom_size; + LANG_SCNG(script_org_size) -= bom_size; + + return script_encoding; + } + + /* script contains NULL bytes -> auto-detection */ + if ((pos1 = memchr(LANG_SCNG(script_org), 0, LANG_SCNG(script_org_size)))) { + /* check if the NULL byte is after the __HALT_COMPILER(); */ + pos2 = LANG_SCNG(script_org); + + while (pos1 - pos2 >= sizeof("__HALT_COMPILER();")-1) { + pos2 = memchr(pos2, '_', pos1 - pos2); + if (!pos2) break; + pos2++; + if (strncasecmp((char*)pos2, "_HALT_COMPILER", sizeof("_HALT_COMPILER")-1) == 0) { + pos2 += sizeof("_HALT_COMPILER")-1; + while (*pos2 == ' ' || + *pos2 == '\t' || + *pos2 == '\r' || + *pos2 == '\n') { + pos2++; + } + if (*pos2 == '(') { + pos2++; + while (*pos2 == ' ' || + *pos2 == '\t' || + *pos2 == '\r' || + *pos2 == '\n') { + pos2++; + } + if (*pos2 == ')') { + pos2++; + while (*pos2 == ' ' || + *pos2 == '\t' || + *pos2 == '\r' || + *pos2 == '\n') { + pos2++; + } + if (*pos2 == ';') { + return NULL; + } + } + } + } + } + /* make best effort if BOM is missing */ + return zend_multibyte_detect_utf_encoding(LANG_SCNG(script_org), LANG_SCNG(script_org_size) TSRMLS_CC); + } + + return NULL; +} + +static const zend_encoding* zend_multibyte_find_script_encoding(TSRMLS_D) +{ + const zend_encoding *script_encoding; + + if (CG(detect_unicode)) { + /* check out bom(byte order mark) and see if containing wchars */ + script_encoding = zend_multibyte_detect_unicode(TSRMLS_C); + if (script_encoding != NULL) { + /* bom or wchar detection is prior to 'script_encoding' option */ + return script_encoding; + } + } + + /* if no script_encoding specified, just leave alone */ + if (!CG(script_encoding_list) || !CG(script_encoding_list_size)) { + return NULL; + } + + /* if multiple encodings specified, detect automagically */ + if (CG(script_encoding_list_size) > 1) { + return zend_multibyte_encoding_detector(LANG_SCNG(script_org), LANG_SCNG(script_org_size), CG(script_encoding_list), CG(script_encoding_list_size) TSRMLS_CC); + } + + return CG(script_encoding_list)[0]; +} + +ZEND_API int zend_multibyte_set_filter(const zend_encoding *onetime_encoding TSRMLS_DC) +{ + const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C); + const zend_encoding *script_encoding = onetime_encoding ? onetime_encoding: zend_multibyte_find_script_encoding(TSRMLS_C); + + if (!script_encoding) { + return FAILURE; + } + + /* judge input/output filter */ + LANG_SCNG(script_encoding) = script_encoding; + LANG_SCNG(input_filter) = NULL; + LANG_SCNG(output_filter) = NULL; + + if (!internal_encoding || LANG_SCNG(script_encoding) == internal_encoding) { + if (!zend_multibyte_check_lexer_compatibility(LANG_SCNG(script_encoding))) { + /* and if not, work around w/ script_encoding -> utf-8 -> script_encoding conversion */ + LANG_SCNG(input_filter) = encoding_filter_script_to_intermediate; + LANG_SCNG(output_filter) = encoding_filter_intermediate_to_script; + } else { + LANG_SCNG(input_filter) = NULL; + LANG_SCNG(output_filter) = NULL; + } + return SUCCESS; + } + + if (zend_multibyte_check_lexer_compatibility(internal_encoding)) { + LANG_SCNG(input_filter) = encoding_filter_script_to_internal; + LANG_SCNG(output_filter) = NULL; + } else if (zend_multibyte_check_lexer_compatibility(LANG_SCNG(script_encoding))) { + LANG_SCNG(input_filter) = NULL; + LANG_SCNG(output_filter) = encoding_filter_script_to_internal; + } else { + /* both script and internal encodings are incompatible w/ flex */ + LANG_SCNG(input_filter) = encoding_filter_script_to_intermediate; + LANG_SCNG(output_filter) = encoding_filter_intermediate_to_internal; + } + + return 0; +} + +ZEND_API int open_file_for_scanning(zend_file_handle *file_handle TSRMLS_DC) +{ + const char *file_path = NULL; + char *buf; + size_t size, offset = 0; + + /* The shebang line was read, get the current position to obtain the buffer start */ + if (CG(start_lineno) == 2 && file_handle->type == ZEND_HANDLE_FP && file_handle->handle.fp) { + if ((offset = ftell(file_handle->handle.fp)) == -1) { + offset = 0; + } + } + + if (zend_stream_fixup(file_handle, &buf, &size TSRMLS_CC) == FAILURE) { + return FAILURE; + } + + zend_llist_add_element(&CG(open_files), file_handle); + if (file_handle->handle.stream.handle >= (void*)file_handle && file_handle->handle.stream.handle <= (void*)(file_handle+1)) { + zend_file_handle *fh = (zend_file_handle*)zend_llist_get_last(&CG(open_files)); + size_t diff = (char*)file_handle->handle.stream.handle - (char*)file_handle; + fh->handle.stream.handle = (void*)(((char*)fh) + diff); + file_handle->handle.stream.handle = fh->handle.stream.handle; + } + + /* Reset the scanner for scanning the new file */ + SCNG(yy_in) = file_handle; + SCNG(yy_start) = NULL; + + if (size != -1) { + if (CG(multibyte)) { + SCNG(script_org) = (unsigned char*)buf; + SCNG(script_org_size) = size; + SCNG(script_filtered) = NULL; + + zend_multibyte_set_filter(NULL TSRMLS_CC); + + if (SCNG(input_filter)) { + if ((size_t)-1 == SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC)) { + zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected " + "encoding \"%s\" to a compatible encoding", zend_multibyte_get_encoding_name(LANG_SCNG(script_encoding))); + } + buf = (char*)SCNG(script_filtered); + size = SCNG(script_filtered_size); + } + } + SCNG(yy_start) = (unsigned char *)buf - offset; + yy_scan_buffer(buf, size TSRMLS_CC); + } else { + zend_error_noreturn(E_COMPILE_ERROR, "zend_stream_mmap() failed"); + } + + BEGIN(INITIAL); + + if (file_handle->opened_path) { + file_path = file_handle->opened_path; + } else { + file_path = file_handle->filename; + } + + zend_set_compiled_filename(file_path TSRMLS_CC); + + if (CG(start_lineno)) { + CG(zend_lineno) = CG(start_lineno); + CG(start_lineno) = 0; + } else { + CG(zend_lineno) = 1; + } + + CG(increment_lineno) = 0; + return SUCCESS; +} +END_EXTERN_C() + + +ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC) +{ + zend_lex_state original_lex_state; + zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array)); + zend_op_array *original_active_op_array = CG(active_op_array); + zend_op_array *retval=NULL; + int compiler_result; + zend_bool compilation_successful=0; + znode retval_znode; + zend_bool original_in_compilation = CG(in_compilation); + + retval_znode.op_type = IS_CONST; + retval_znode.u.constant.type = IS_LONG; + retval_znode.u.constant.value.lval = 1; + Z_UNSET_ISREF(retval_znode.u.constant); + Z_SET_REFCOUNT(retval_znode.u.constant, 1); + + zend_save_lexical_state(&original_lex_state TSRMLS_CC); + + retval = op_array; /* success oriented */ + + if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) { + if (type==ZEND_REQUIRE) { + zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC); + zend_bailout(); + } else { + zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC); + } + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + zend_init_compiler_context(TSRMLS_C); + compiler_result = zendparse(TSRMLS_C); + zend_do_return(&retval_znode, 0 TSRMLS_CC); + CG(in_compilation) = original_in_compilation; + if (compiler_result==1) { /* parser error */ + zend_bailout(); + } + compilation_successful=1; + } + + if (retval) { + CG(active_op_array) = original_active_op_array; + if (compilation_successful) { + pass_two(op_array TSRMLS_CC); + zend_release_labels(TSRMLS_C); + } else { + efree(op_array); + retval = NULL; + } + } + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + return retval; +} + + +zend_op_array *compile_filename(int type, zval *filename TSRMLS_DC) +{ + zend_file_handle file_handle; + zval tmp; + zend_op_array *retval; + char *opened_path = NULL; + + if (filename->type != IS_STRING) { + tmp = *filename; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + filename = &tmp; + } + file_handle.filename = filename->value.str.val; + file_handle.free_filename = 0; + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.opened_path = NULL; + file_handle.handle.fp = NULL; + + retval = zend_compile_file(&file_handle, type TSRMLS_CC); + if (retval && file_handle.handle.stream.handle) { + int dummy = 1; + + if (!file_handle.opened_path) { + file_handle.opened_path = opened_path = estrndup(filename->value.str.val, filename->value.str.len); + } + + zend_hash_add(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1, (void *)&dummy, sizeof(int), NULL); + + if (opened_path) { + efree(opened_path); + } + } + zend_destroy_file_handle(&file_handle TSRMLS_CC); + + if (filename==&tmp) { + zval_dtor(&tmp); + } + return retval; +} + +ZEND_API int zend_prepare_string_for_scanning(zval *str, char *filename TSRMLS_DC) +{ + char *buf; + size_t size; + + /* enforce two trailing NULLs for flex... */ + if (IS_INTERNED(str->value.str.val)) { + char *tmp = safe_emalloc(1, str->value.str.len, ZEND_MMAP_AHEAD); + memcpy(tmp, str->value.str.val, str->value.str.len + ZEND_MMAP_AHEAD); + str->value.str.val = tmp; + } else { + str->value.str.val = safe_erealloc(str->value.str.val, 1, str->value.str.len, ZEND_MMAP_AHEAD); + } + + memset(str->value.str.val + str->value.str.len, 0, ZEND_MMAP_AHEAD); + + SCNG(yy_in) = NULL; + SCNG(yy_start) = NULL; + + buf = str->value.str.val; + size = str->value.str.len; + + if (CG(multibyte)) { + SCNG(script_org) = (unsigned char*)buf; + SCNG(script_org_size) = size; + SCNG(script_filtered) = NULL; + + zend_multibyte_set_filter(zend_multibyte_get_internal_encoding(TSRMLS_C) TSRMLS_CC); + + if (SCNG(input_filter)) { + if ((size_t)-1 == SCNG(input_filter)(&SCNG(script_filtered), &SCNG(script_filtered_size), SCNG(script_org), SCNG(script_org_size) TSRMLS_CC)) { + zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected " + "encoding \"%s\" to a compatible encoding", zend_multibyte_get_encoding_name(LANG_SCNG(script_encoding))); + } + buf = (char*)SCNG(script_filtered); + size = SCNG(script_filtered_size); + } + } + + yy_scan_buffer(buf, size TSRMLS_CC); + + zend_set_compiled_filename(filename TSRMLS_CC); + CG(zend_lineno) = 1; + CG(increment_lineno) = 0; + return SUCCESS; +} + + +ZEND_API size_t zend_get_scanned_file_offset(TSRMLS_D) +{ + size_t offset = SCNG(yy_cursor) - SCNG(yy_start); + if (SCNG(input_filter)) { + size_t original_offset = offset, length = 0; + do { + unsigned char *p = NULL; + if ((size_t)-1 == SCNG(input_filter)(&p, &length, SCNG(script_org), offset TSRMLS_CC)) { + return (size_t)-1; + } + efree(p); + if (length > original_offset) { + offset--; + } else if (length < original_offset) { + offset++; + } + } while (original_offset != length); + } + return offset; +} + + +zend_op_array *compile_string(zval *source_string, char *filename TSRMLS_DC) +{ + zend_lex_state original_lex_state; + zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array)); + zend_op_array *original_active_op_array = CG(active_op_array); + zend_op_array *retval; + zval tmp; + int compiler_result; + zend_bool original_in_compilation = CG(in_compilation); + + if (source_string->value.str.len==0) { + efree(op_array); + return NULL; + } + + CG(in_compilation) = 1; + + tmp = *source_string; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + source_string = &tmp; + + zend_save_lexical_state(&original_lex_state TSRMLS_CC); + if (zend_prepare_string_for_scanning(source_string, filename TSRMLS_CC)==FAILURE) { + efree(op_array); + retval = NULL; + } else { + zend_bool orig_interactive = CG(interactive); + + CG(interactive) = 0; + init_op_array(op_array, ZEND_EVAL_CODE, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); + CG(interactive) = orig_interactive; + CG(active_op_array) = op_array; + zend_init_compiler_context(TSRMLS_C); + BEGIN(ST_IN_SCRIPTING); + compiler_result = zendparse(TSRMLS_C); + + if (SCNG(script_filtered)) { + efree(SCNG(script_filtered)); + SCNG(script_filtered) = NULL; + } + + if (compiler_result==1) { + CG(active_op_array) = original_active_op_array; + CG(unclean_shutdown)=1; + destroy_op_array(op_array TSRMLS_CC); + efree(op_array); + retval = NULL; + } else { + zend_do_return(NULL, 0 TSRMLS_CC); + CG(active_op_array) = original_active_op_array; + pass_two(op_array TSRMLS_CC); + zend_release_labels(TSRMLS_C); + retval = op_array; + } + } + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + zval_dtor(&tmp); + CG(in_compilation) = original_in_compilation; + return retval; +} + + +BEGIN_EXTERN_C() +int highlight_file(char *filename, zend_syntax_highlighter_ini *syntax_highlighter_ini TSRMLS_DC) +{ + zend_lex_state original_lex_state; + zend_file_handle file_handle; + + file_handle.type = ZEND_HANDLE_FILENAME; + file_handle.filename = filename; + file_handle.free_filename = 0; + file_handle.opened_path = NULL; + zend_save_lexical_state(&original_lex_state TSRMLS_CC); + if (open_file_for_scanning(&file_handle TSRMLS_CC)==FAILURE) { + zend_message_dispatcher(ZMSG_FAILED_HIGHLIGHT_FOPEN, filename TSRMLS_CC); + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + return FAILURE; + } + zend_highlight(syntax_highlighter_ini TSRMLS_CC); + if (SCNG(script_filtered)) { + efree(SCNG(script_filtered)); + SCNG(script_filtered) = NULL; + } + zend_destroy_file_handle(&file_handle TSRMLS_CC); + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + return SUCCESS; +} + +int highlight_string(zval *str, zend_syntax_highlighter_ini *syntax_highlighter_ini, char *str_name TSRMLS_DC) +{ + zend_lex_state original_lex_state; + zval tmp = *str; + + str = &tmp; + zval_copy_ctor(str); + zend_save_lexical_state(&original_lex_state TSRMLS_CC); + if (zend_prepare_string_for_scanning(str, str_name TSRMLS_CC)==FAILURE) { + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + return FAILURE; + } + BEGIN(INITIAL); + zend_highlight(syntax_highlighter_ini TSRMLS_CC); + if (SCNG(script_filtered)) { + efree(SCNG(script_filtered)); + SCNG(script_filtered) = NULL; + } + zend_restore_lexical_state(&original_lex_state TSRMLS_CC); + zval_dtor(str); + return SUCCESS; +} + +ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter, const zend_encoding *old_encoding TSRMLS_DC) +{ + size_t length; + unsigned char *new_yy_start; + + /* convert and set */ + if (!SCNG(input_filter)) { + if (SCNG(script_filtered)) { + efree(SCNG(script_filtered)); + SCNG(script_filtered) = NULL; + } + SCNG(script_filtered_size) = 0; + length = SCNG(script_org_size); + new_yy_start = SCNG(script_org); + } else { + if ((size_t)-1 == SCNG(input_filter)(&new_yy_start, &length, SCNG(script_org), SCNG(script_org_size) TSRMLS_CC)) { + zend_error_noreturn(E_COMPILE_ERROR, "Could not convert the script from the detected " + "encoding \"%s\" to a compatible encoding", zend_multibyte_get_encoding_name(LANG_SCNG(script_encoding))); + } + SCNG(script_filtered) = new_yy_start; + SCNG(script_filtered_size) = length; + } + + SCNG(yy_cursor) = new_yy_start + (SCNG(yy_cursor) - SCNG(yy_start)); + SCNG(yy_marker) = new_yy_start + (SCNG(yy_marker) - SCNG(yy_start)); + SCNG(yy_text) = new_yy_start + (SCNG(yy_text) - SCNG(yy_start)); + SCNG(yy_limit) = new_yy_start + (SCNG(yy_limit) - SCNG(yy_start)); + + SCNG(yy_start) = new_yy_start; +} + + +# define zend_copy_value(zendlval, yytext, yyleng) \ + if (SCNG(output_filter)) { \ + size_t sz = 0; \ + SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC); \ + zendlval->value.str.len = sz; \ + } else { \ + zendlval->value.str.val = (char *) estrndup(yytext, yyleng); \ + zendlval->value.str.len = yyleng; \ + } + +static void zend_scan_escape_string(zval *zendlval, char *str, int len, char quote_type TSRMLS_DC) +{ + register char *s, *t; + char *end; + + ZVAL_STRINGL(zendlval, str, len, 1); + + /* convert escape sequences */ + s = t = zendlval->value.str.val; + end = s+zendlval->value.str.len; + while (s<end) { + if (*s=='\\') { + s++; + if (s >= end) { + *t++ = '\\'; + break; + } + + switch(*s) { + case 'n': + *t++ = '\n'; + zendlval->value.str.len--; + break; + case 'r': + *t++ = '\r'; + zendlval->value.str.len--; + break; + case 't': + *t++ = '\t'; + zendlval->value.str.len--; + break; + case 'f': + *t++ = '\f'; + zendlval->value.str.len--; + break; + case 'v': + *t++ = '\v'; + zendlval->value.str.len--; + break; + case 'e': + *t++ = '\e'; + zendlval->value.str.len--; + break; + case '"': + case '`': + if (*s != quote_type) { + *t++ = '\\'; + *t++ = *s; + break; + } + case '\\': + case '$': + *t++ = *s; + zendlval->value.str.len--; + break; + case 'x': + case 'X': + if (ZEND_IS_HEX(*(s+1))) { + char hex_buf[3] = { 0, 0, 0 }; + + zendlval->value.str.len--; /* for the 'x' */ + + hex_buf[0] = *(++s); + zendlval->value.str.len--; + if (ZEND_IS_HEX(*(s+1))) { + hex_buf[1] = *(++s); + zendlval->value.str.len--; + } + *t++ = (char) strtol(hex_buf, NULL, 16); + } else { + *t++ = '\\'; + *t++ = *s; + } + break; + default: + /* check for an octal */ + if (ZEND_IS_OCT(*s)) { + char octal_buf[4] = { 0, 0, 0, 0 }; + + octal_buf[0] = *s; + zendlval->value.str.len--; + if (ZEND_IS_OCT(*(s+1))) { + octal_buf[1] = *(++s); + zendlval->value.str.len--; + if (ZEND_IS_OCT(*(s+1))) { + octal_buf[2] = *(++s); + zendlval->value.str.len--; + } + } + *t++ = (char) strtol(octal_buf, NULL, 8); + } else { + *t++ = '\\'; + *t++ = *s; + } + break; + } + } else { + *t++ = *s; + } + + if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) { + CG(zend_lineno)++; + } + s++; + } + *t = 0; + if (SCNG(output_filter)) { + size_t sz = 0; + s = zendlval->value.str.val; + SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)s, (size_t)zendlval->value.str.len TSRMLS_CC); + zendlval->value.str.len = sz; + efree(s); + } +} + + +int lex_scan(zval *zendlval TSRMLS_DC) +{ +restart: + SCNG(yy_text) = YYCURSOR; + +yymore_restart: + +/*!re2c +re2c:yyfill:check = 0; +LNUM [0-9]+ +DNUM ([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*) +EXPONENT_DNUM (({LNUM}|{DNUM})[eE][+-]?{LNUM}) +HNUM "0x"[0-9a-fA-F]+ +BNUM "0b"[01]+ +LABEL [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]* +WHITESPACE [ \n\r\t]+ +TABS_AND_SPACES [ \t]* +TOKENS [;:,.\[\]()|^&+-/*=%!~$<>?@] +ANY_CHAR [^] +NEWLINE ("\r"|"\n"|"\r\n") + +/* compute yyleng before each rule */ +<!*> := yyleng = YYCURSOR - SCNG(yy_text); + + +<ST_IN_SCRIPTING>"exit" { + return T_EXIT; +} + +<ST_IN_SCRIPTING>"die" { + return T_EXIT; +} + +<ST_IN_SCRIPTING>"function" { + return T_FUNCTION; +} + +<ST_IN_SCRIPTING>"const" { + return T_CONST; +} + +<ST_IN_SCRIPTING>"return" { + return T_RETURN; +} + +<ST_IN_SCRIPTING>"try" { + return T_TRY; +} + +<ST_IN_SCRIPTING>"catch" { + return T_CATCH; +} + +<ST_IN_SCRIPTING>"throw" { + return T_THROW; +} + +<ST_IN_SCRIPTING>"if" { + return T_IF; +} + +<ST_IN_SCRIPTING>"elseif" { + return T_ELSEIF; +} + +<ST_IN_SCRIPTING>"endif" { + return T_ENDIF; +} + +<ST_IN_SCRIPTING>"else" { + return T_ELSE; +} + +<ST_IN_SCRIPTING>"while" { + return T_WHILE; +} + +<ST_IN_SCRIPTING>"endwhile" { + return T_ENDWHILE; +} + +<ST_IN_SCRIPTING>"do" { + return T_DO; +} + +<ST_IN_SCRIPTING>"for" { + return T_FOR; +} + +<ST_IN_SCRIPTING>"endfor" { + return T_ENDFOR; +} + +<ST_IN_SCRIPTING>"foreach" { + return T_FOREACH; +} + +<ST_IN_SCRIPTING>"endforeach" { + return T_ENDFOREACH; +} + +<ST_IN_SCRIPTING>"declare" { + return T_DECLARE; +} + +<ST_IN_SCRIPTING>"enddeclare" { + return T_ENDDECLARE; +} + +<ST_IN_SCRIPTING>"instanceof" { + return T_INSTANCEOF; +} + +<ST_IN_SCRIPTING>"as" { + return T_AS; +} + +<ST_IN_SCRIPTING>"switch" { + return T_SWITCH; +} + +<ST_IN_SCRIPTING>"endswitch" { + return T_ENDSWITCH; +} + +<ST_IN_SCRIPTING>"case" { + return T_CASE; +} + +<ST_IN_SCRIPTING>"default" { + return T_DEFAULT; +} + +<ST_IN_SCRIPTING>"break" { + return T_BREAK; +} + +<ST_IN_SCRIPTING>"continue" { + return T_CONTINUE; +} + +<ST_IN_SCRIPTING>"goto" { + return T_GOTO; +} + +<ST_IN_SCRIPTING>"echo" { + return T_ECHO; +} + +<ST_IN_SCRIPTING>"print" { + return T_PRINT; +} + +<ST_IN_SCRIPTING>"class" { + return T_CLASS; +} + +<ST_IN_SCRIPTING>"interface" { + return T_INTERFACE; +} + +<ST_IN_SCRIPTING>"trait" { + return T_TRAIT; +} + +<ST_IN_SCRIPTING>"extends" { + return T_EXTENDS; +} + +<ST_IN_SCRIPTING>"implements" { + return T_IMPLEMENTS; +} + +<ST_IN_SCRIPTING>"->" { + yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC); + return T_OBJECT_OPERATOR; +} + +<ST_IN_SCRIPTING,ST_LOOKING_FOR_PROPERTY>{WHITESPACE}+ { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + HANDLE_NEWLINES(yytext, yyleng); + return T_WHITESPACE; +} + +<ST_LOOKING_FOR_PROPERTY>"->" { + return T_OBJECT_OPERATOR; +} + +<ST_LOOKING_FOR_PROPERTY>{LABEL} { + yy_pop_state(TSRMLS_C); + zend_copy_value(zendlval, yytext, yyleng); + zendlval->type = IS_STRING; + return T_STRING; +} + +<ST_LOOKING_FOR_PROPERTY>{ANY_CHAR} { + yyless(0); + yy_pop_state(TSRMLS_C); + goto restart; +} + +<ST_IN_SCRIPTING>"::" { + return T_PAAMAYIM_NEKUDOTAYIM; +} + +<ST_IN_SCRIPTING>"\\" { + return T_NS_SEPARATOR; +} + +<ST_IN_SCRIPTING>"new" { + return T_NEW; +} + +<ST_IN_SCRIPTING>"clone" { + return T_CLONE; +} + +<ST_IN_SCRIPTING>"var" { + return T_VAR; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("int"|"integer"){TABS_AND_SPACES}")" { + return T_INT_CAST; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("real"|"double"|"float"){TABS_AND_SPACES}")" { + return T_DOUBLE_CAST; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("string"|"binary"){TABS_AND_SPACES}")" { + return T_STRING_CAST; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"array"{TABS_AND_SPACES}")" { + return T_ARRAY_CAST; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}"object"{TABS_AND_SPACES}")" { + return T_OBJECT_CAST; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("bool"|"boolean"){TABS_AND_SPACES}")" { + return T_BOOL_CAST; +} + +<ST_IN_SCRIPTING>"("{TABS_AND_SPACES}("unset"){TABS_AND_SPACES}")" { + return T_UNSET_CAST; +} + +<ST_IN_SCRIPTING>"eval" { + return T_EVAL; +} + +<ST_IN_SCRIPTING>"include" { + return T_INCLUDE; +} + +<ST_IN_SCRIPTING>"include_once" { + return T_INCLUDE_ONCE; +} + +<ST_IN_SCRIPTING>"require" { + return T_REQUIRE; +} + +<ST_IN_SCRIPTING>"require_once" { + return T_REQUIRE_ONCE; +} + +<ST_IN_SCRIPTING>"namespace" { + return T_NAMESPACE; +} + +<ST_IN_SCRIPTING>"use" { + return T_USE; +} + +<ST_IN_SCRIPTING>"insteadof" { + return T_INSTEADOF; +} + +<ST_IN_SCRIPTING>"global" { + return T_GLOBAL; +} + +<ST_IN_SCRIPTING>"isset" { + return T_ISSET; +} + +<ST_IN_SCRIPTING>"empty" { + return T_EMPTY; +} + +<ST_IN_SCRIPTING>"__halt_compiler" { + return T_HALT_COMPILER; +} + +<ST_IN_SCRIPTING>"static" { + return T_STATIC; +} + +<ST_IN_SCRIPTING>"abstract" { + return T_ABSTRACT; +} + +<ST_IN_SCRIPTING>"final" { + return T_FINAL; +} + +<ST_IN_SCRIPTING>"private" { + return T_PRIVATE; +} + +<ST_IN_SCRIPTING>"protected" { + return T_PROTECTED; +} + +<ST_IN_SCRIPTING>"public" { + return T_PUBLIC; +} + +<ST_IN_SCRIPTING>"unset" { + return T_UNSET; +} + +<ST_IN_SCRIPTING>"=>" { + return T_DOUBLE_ARROW; +} + +<ST_IN_SCRIPTING>"list" { + return T_LIST; +} + +<ST_IN_SCRIPTING>"array" { + return T_ARRAY; +} + +<ST_IN_SCRIPTING>"callable" { + return T_CALLABLE; +} + +<ST_IN_SCRIPTING>"++" { + return T_INC; +} + +<ST_IN_SCRIPTING>"--" { + return T_DEC; +} + +<ST_IN_SCRIPTING>"===" { + return T_IS_IDENTICAL; +} + +<ST_IN_SCRIPTING>"!==" { + return T_IS_NOT_IDENTICAL; +} + +<ST_IN_SCRIPTING>"==" { + return T_IS_EQUAL; +} + +<ST_IN_SCRIPTING>"!="|"<>" { + return T_IS_NOT_EQUAL; +} + +<ST_IN_SCRIPTING>"<=" { + return T_IS_SMALLER_OR_EQUAL; +} + +<ST_IN_SCRIPTING>">=" { + return T_IS_GREATER_OR_EQUAL; +} + +<ST_IN_SCRIPTING>"+=" { + return T_PLUS_EQUAL; +} + +<ST_IN_SCRIPTING>"-=" { + return T_MINUS_EQUAL; +} + +<ST_IN_SCRIPTING>"*=" { + return T_MUL_EQUAL; +} + +<ST_IN_SCRIPTING>"/=" { + return T_DIV_EQUAL; +} + +<ST_IN_SCRIPTING>".=" { + return T_CONCAT_EQUAL; +} + +<ST_IN_SCRIPTING>"%=" { + return T_MOD_EQUAL; +} + +<ST_IN_SCRIPTING>"<<=" { + return T_SL_EQUAL; +} + +<ST_IN_SCRIPTING>">>=" { + return T_SR_EQUAL; +} + +<ST_IN_SCRIPTING>"&=" { + return T_AND_EQUAL; +} + +<ST_IN_SCRIPTING>"|=" { + return T_OR_EQUAL; +} + +<ST_IN_SCRIPTING>"^=" { + return T_XOR_EQUAL; +} + +<ST_IN_SCRIPTING>"||" { + return T_BOOLEAN_OR; +} + +<ST_IN_SCRIPTING>"&&" { + return T_BOOLEAN_AND; +} + +<ST_IN_SCRIPTING>"OR" { + return T_LOGICAL_OR; +} + +<ST_IN_SCRIPTING>"AND" { + return T_LOGICAL_AND; +} + +<ST_IN_SCRIPTING>"XOR" { + return T_LOGICAL_XOR; +} + +<ST_IN_SCRIPTING>"<<" { + return T_SL; +} + +<ST_IN_SCRIPTING>">>" { + return T_SR; +} + +<ST_IN_SCRIPTING>{TOKENS} { + return yytext[0]; +} + + +<ST_IN_SCRIPTING>"{" { + yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); + return '{'; +} + + +<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"${" { + yy_push_state(ST_LOOKING_FOR_VARNAME TSRMLS_CC); + return T_DOLLAR_OPEN_CURLY_BRACES; +} + + +<ST_IN_SCRIPTING>"}" { + RESET_DOC_COMMENT(); + if (!zend_stack_is_empty(&SCNG(state_stack))) { + yy_pop_state(TSRMLS_C); + } + return '}'; +} + + +<ST_LOOKING_FOR_VARNAME>{LABEL} { + zend_copy_value(zendlval, yytext, yyleng); + zendlval->type = IS_STRING; + yy_pop_state(TSRMLS_C); + yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); + return T_STRING_VARNAME; +} + + +<ST_LOOKING_FOR_VARNAME>{ANY_CHAR} { + yyless(0); + yy_pop_state(TSRMLS_C); + yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); + goto restart; +} + +<ST_IN_SCRIPTING>{BNUM} { + char *bin = yytext + 2; /* Skip "0b" */ + int len = yyleng - 2; + + /* Skip any leading 0s */ + while (*bin == '0') { + ++bin; + --len; + } + + if (len < SIZEOF_LONG * 8) { + if (len == 0) { + zendlval->value.lval = 0; + } else { + zendlval->value.lval = strtol(bin, NULL, 2); + } + zendlval->type = IS_LONG; + return T_LNUMBER; + } else { + zendlval->value.dval = zend_bin_strtod(bin, NULL); + zendlval->type = IS_DOUBLE; + return T_DNUMBER; + } +} + +<ST_IN_SCRIPTING>{LNUM} { + if (yyleng < MAX_LENGTH_OF_LONG - 1) { /* Won't overflow */ + zendlval->value.lval = strtol(yytext, NULL, 0); + } else { + errno = 0; + zendlval->value.lval = strtol(yytext, NULL, 0); + if (errno == ERANGE) { /* Overflow */ + if (yytext[0] == '0') { /* octal overflow */ + zendlval->value.dval = zend_oct_strtod(yytext, NULL); + } else { + zendlval->value.dval = zend_strtod(yytext, NULL); + } + zendlval->type = IS_DOUBLE; + return T_DNUMBER; + } + } + + zendlval->type = IS_LONG; + return T_LNUMBER; +} + +<ST_IN_SCRIPTING>{HNUM} { + char *hex = yytext + 2; /* Skip "0x" */ + int len = yyleng - 2; + + /* Skip any leading 0s */ + while (*hex == '0') { + hex++; + len--; + } + + if (len < SIZEOF_LONG * 2 || (len == SIZEOF_LONG * 2 && *hex <= '7')) { + if (len == 0) { + zendlval->value.lval = 0; + } else { + zendlval->value.lval = strtol(hex, NULL, 16); + } + zendlval->type = IS_LONG; + return T_LNUMBER; + } else { + zendlval->value.dval = zend_hex_strtod(hex, NULL); + zendlval->type = IS_DOUBLE; + return T_DNUMBER; + } +} + +<ST_VAR_OFFSET>[0]|([1-9][0-9]*) { /* Offset could be treated as a long */ + if (yyleng < MAX_LENGTH_OF_LONG - 1 || (yyleng == MAX_LENGTH_OF_LONG - 1 && strcmp(yytext, long_min_digits) < 0)) { + zendlval->value.lval = strtol(yytext, NULL, 10); + zendlval->type = IS_LONG; + } else { + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + } + return T_NUM_STRING; +} + +<ST_VAR_OFFSET>{LNUM}|{HNUM}|{BNUM} { /* Offset must be treated as a string */ + zendlval->value.str.val = (char *)estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + return T_NUM_STRING; +} + +<ST_IN_SCRIPTING>{DNUM}|{EXPONENT_DNUM} { + zendlval->value.dval = zend_strtod(yytext, NULL); + zendlval->type = IS_DOUBLE; + return T_DNUMBER; +} + +<ST_IN_SCRIPTING>"__CLASS__" { + const char *class_name = NULL; + + if (CG(active_class_entry) + && (ZEND_ACC_TRAIT == + (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT))) { + /* We create a special __CLASS__ constant that is going to be resolved + at run-time */ + zendlval->value.str.len = sizeof("__CLASS__")-1; + zendlval->value.str.val = estrndup("__CLASS__", zendlval->value.str.len); + zendlval->type = IS_CONSTANT; + } else { + if (CG(active_class_entry)) { + class_name = CG(active_class_entry)->name; + } + + if (!class_name) { + class_name = ""; + } + + zendlval->value.str.len = strlen(class_name); + zendlval->value.str.val = estrndup(class_name, zendlval->value.str.len); + zendlval->type = IS_STRING; + } + return T_CLASS_C; +} + +<ST_IN_SCRIPTING>"__TRAIT__" { + const char *trait_name = NULL; + + if (CG(active_class_entry) + && (ZEND_ACC_TRAIT == + (CG(active_class_entry)->ce_flags & ZEND_ACC_TRAIT))) { + trait_name = CG(active_class_entry)->name; + } + + if (!trait_name) { + trait_name = ""; + } + + zendlval->value.str.len = strlen(trait_name); + zendlval->value.str.val = estrndup(trait_name, zendlval->value.str.len); + zendlval->type = IS_STRING; + + return T_TRAIT_C; +} + +<ST_IN_SCRIPTING>"__FUNCTION__" { + const char *func_name = NULL; + + if (CG(active_op_array)) { + func_name = CG(active_op_array)->function_name; + } + + if (!func_name) { + func_name = ""; + } + zendlval->value.str.len = strlen(func_name); + zendlval->value.str.val = estrndup(func_name, zendlval->value.str.len); + zendlval->type = IS_STRING; + return T_FUNC_C; +} + +<ST_IN_SCRIPTING>"__METHOD__" { + const char *class_name = CG(active_class_entry) ? CG(active_class_entry)->name : NULL; + const char *func_name = CG(active_op_array)? CG(active_op_array)->function_name : NULL; + size_t len = 0; + + if (class_name) { + len += strlen(class_name) + 2; + } + if (func_name) { + len += strlen(func_name); + } + + zendlval->value.str.len = zend_spprintf(&zendlval->value.str.val, 0, "%s%s%s", + class_name ? class_name : "", + class_name && func_name ? "::" : "", + func_name ? func_name : "" + ); + zendlval->type = IS_STRING; + return T_METHOD_C; +} + +<ST_IN_SCRIPTING>"__LINE__" { + zendlval->value.lval = CG(zend_lineno); + zendlval->type = IS_LONG; + return T_LINE; +} + +<ST_IN_SCRIPTING>"__FILE__" { + char *filename = zend_get_compiled_filename(TSRMLS_C); + + if (!filename) { + filename = ""; + } + zendlval->value.str.len = strlen(filename); + zendlval->value.str.val = estrndup(filename, zendlval->value.str.len); + zendlval->type = IS_STRING; + return T_FILE; +} + +<ST_IN_SCRIPTING>"__DIR__" { + char *filename = zend_get_compiled_filename(TSRMLS_C); + const size_t filename_len = strlen(filename); + char *dirname; + + if (!filename) { + filename = ""; + } + + dirname = estrndup(filename, filename_len); + zend_dirname(dirname, filename_len); + + if (strcmp(dirname, ".") == 0) { + dirname = erealloc(dirname, MAXPATHLEN); +#if HAVE_GETCWD + VCWD_GETCWD(dirname, MAXPATHLEN); +#elif HAVE_GETWD + VCWD_GETWD(dirname); +#endif + } + + zendlval->value.str.len = strlen(dirname); + zendlval->value.str.val = dirname; + zendlval->type = IS_STRING; + return T_DIR; +} + +<ST_IN_SCRIPTING>"__NAMESPACE__" { + if (CG(current_namespace)) { + *zendlval = *CG(current_namespace); + zval_copy_ctor(zendlval); + } else { + ZVAL_EMPTY_STRING(zendlval); + } + return T_NS_C; +} + +<INITIAL>"<script"{WHITESPACE}+"language"{WHITESPACE}*"="{WHITESPACE}*("php"|"\"php\""|"'php'"){WHITESPACE}*">" { + YYCTYPE *bracket = (YYCTYPE*)zend_memrchr(yytext, '<', yyleng - (sizeof("script language=php>") - 1)); + + if (bracket != SCNG(yy_text)) { + /* Handle previously scanned HTML, as possible <script> tags found are assumed to not be PHP's */ + YYCURSOR = bracket; + goto inline_html; + } + + HANDLE_NEWLINES(yytext, yyleng); + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + BEGIN(ST_IN_SCRIPTING); + return T_OPEN_TAG; +} + + +<INITIAL>"<%=" { + if (CG(asp_tags)) { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + BEGIN(ST_IN_SCRIPTING); + return T_OPEN_TAG_WITH_ECHO; + } else { + goto inline_char_handler; + } +} + + +<INITIAL>"<?=" { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + BEGIN(ST_IN_SCRIPTING); + return T_OPEN_TAG_WITH_ECHO; +} + + +<INITIAL>"<%" { + if (CG(asp_tags)) { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + BEGIN(ST_IN_SCRIPTING); + return T_OPEN_TAG; + } else { + goto inline_char_handler; + } +} + + +<INITIAL>"<?php"([ \t]|{NEWLINE}) { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + HANDLE_NEWLINE(yytext[yyleng-1]); + BEGIN(ST_IN_SCRIPTING); + return T_OPEN_TAG; +} + + +<INITIAL>"<?" { + if (CG(short_tags)) { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + BEGIN(ST_IN_SCRIPTING); + return T_OPEN_TAG; + } else { + goto inline_char_handler; + } +} + +<INITIAL>{ANY_CHAR} { + if (YYCURSOR > YYLIMIT) { + return 0; + } + +inline_char_handler: + + while (1) { + YYCTYPE *ptr = memchr(YYCURSOR, '<', YYLIMIT - YYCURSOR); + + YYCURSOR = ptr ? ptr + 1 : YYLIMIT; + + if (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR) { + case '?': + if (CG(short_tags) || !strncasecmp((char*)YYCURSOR + 1, "php", 3) || (*(YYCURSOR + 1) == '=')) { /* Assume [ \t\n\r] follows "php" */ + break; + } + continue; + case '%': + if (CG(asp_tags)) { + break; + } + continue; + case 's': + case 'S': + /* Probably NOT an opening PHP <script> tag, so don't end the HTML chunk yet + * If it is, the PHP <script> tag rule checks for any HTML scanned before it */ + YYCURSOR--; + yymore(); + default: + continue; + } + + YYCURSOR--; + } + + break; + } + +inline_html: + yyleng = YYCURSOR - SCNG(yy_text); + + if (SCNG(output_filter)) { + int readsize; + size_t sz = 0; + readsize = SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)yytext, (size_t)yyleng TSRMLS_CC); + zendlval->value.str.len = sz; + if (readsize < yyleng) { + yyless(readsize); + } + } else { + zendlval->value.str.val = (char *) estrndup(yytext, yyleng); + zendlval->value.str.len = yyleng; + } + zendlval->type = IS_STRING; + HANDLE_NEWLINES(yytext, yyleng); + return T_INLINE_HTML; +} + + +/* Make sure a label character follows "->", otherwise there is no property + * and "->" will be taken literally + */ +<ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{LABEL}"->"[a-zA-Z_\x7f-\xff] { + yyless(yyleng - 3); + yy_push_state(ST_LOOKING_FOR_PROPERTY TSRMLS_CC); + zend_copy_value(zendlval, (yytext+1), (yyleng-1)); + zendlval->type = IS_STRING; + return T_VARIABLE; +} + +/* A [ always designates a variable offset, regardless of what follows + */ +<ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE>"$"{LABEL}"[" { + yyless(yyleng - 1); + yy_push_state(ST_VAR_OFFSET TSRMLS_CC); + zend_copy_value(zendlval, (yytext+1), (yyleng-1)); + zendlval->type = IS_STRING; + return T_VARIABLE; +} + +<ST_IN_SCRIPTING,ST_DOUBLE_QUOTES,ST_HEREDOC,ST_BACKQUOTE,ST_VAR_OFFSET>"$"{LABEL} { + zend_copy_value(zendlval, (yytext+1), (yyleng-1)); + zendlval->type = IS_STRING; + return T_VARIABLE; +} + +<ST_VAR_OFFSET>"]" { + yy_pop_state(TSRMLS_C); + return ']'; +} + +<ST_VAR_OFFSET>{TOKENS}|[{}"`] { + /* Only '[' can be valid, but returning other tokens will allow a more explicit parse error */ + return yytext[0]; +} + +<ST_VAR_OFFSET>[ \n\r\t\\'#] { + /* Invalid rule to return a more explicit parse error with proper line number */ + yyless(0); + yy_pop_state(TSRMLS_C); + return T_ENCAPSED_AND_WHITESPACE; +} + +<ST_IN_SCRIPTING,ST_VAR_OFFSET>{LABEL} { + zend_copy_value(zendlval, yytext, yyleng); + zendlval->type = IS_STRING; + return T_STRING; +} + + +<ST_IN_SCRIPTING>"#"|"//" { + while (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR++) { + case '\r': + if (*YYCURSOR == '\n') { + YYCURSOR++; + } + /* fall through */ + case '\n': + CG(zend_lineno)++; + break; + case '%': + if (!CG(asp_tags)) { + continue; + } + /* fall through */ + case '?': + if (*YYCURSOR == '>') { + YYCURSOR--; + break; + } + /* fall through */ + default: + continue; + } + + break; + } + + yyleng = YYCURSOR - SCNG(yy_text); + + return T_COMMENT; +} + +<ST_IN_SCRIPTING>"/*"|"/**"{WHITESPACE} { + int doc_com; + + if (yyleng > 2) { + doc_com = 1; + RESET_DOC_COMMENT(); + } else { + doc_com = 0; + } + + while (YYCURSOR < YYLIMIT) { + if (*YYCURSOR++ == '*' && *YYCURSOR == '/') { + break; + } + } + + if (YYCURSOR < YYLIMIT) { + YYCURSOR++; + } else { + zend_error(E_COMPILE_WARNING, "Unterminated comment starting line %d", CG(zend_lineno)); + } + + yyleng = YYCURSOR - SCNG(yy_text); + HANDLE_NEWLINES(yytext, yyleng); + + if (doc_com) { + CG(doc_comment) = estrndup(yytext, yyleng); + CG(doc_comment_len) = yyleng; + return T_DOC_COMMENT; + } + + return T_COMMENT; +} + +<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? { + zendlval->value.str.val = yytext; /* no copying - intentional */ + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + BEGIN(INITIAL); + return T_CLOSE_TAG; /* implicit ';' at php-end tag */ +} + + +<ST_IN_SCRIPTING>"%>"{NEWLINE}? { + if (CG(asp_tags)) { + BEGIN(INITIAL); + zendlval->value.str.len = yyleng; + zendlval->type = IS_STRING; + zendlval->value.str.val = yytext; /* no copying - intentional */ + return T_CLOSE_TAG; /* implicit ';' at php-end tag */ + } else { + yyless(1); + return yytext[0]; + } +} + + +<ST_IN_SCRIPTING>b?['] { + register char *s, *t; + char *end; + int bprefix = (yytext[0] != '\'') ? 1 : 0; + + while (1) { + if (YYCURSOR < YYLIMIT) { + if (*YYCURSOR == '\'') { + YYCURSOR++; + yyleng = YYCURSOR - SCNG(yy_text); + + break; + } else if (*YYCURSOR++ == '\\' && YYCURSOR < YYLIMIT) { + YYCURSOR++; + } + } else { + yyleng = YYLIMIT - SCNG(yy_text); + + /* Unclosed single quotes; treat similar to double quotes, but without a separate token + * for ' (unrecognized by parser), instead of old flex fallback to "Unexpected character..." + * rule, which continued in ST_IN_SCRIPTING state after the quote */ + return T_ENCAPSED_AND_WHITESPACE; + } + } + + zendlval->value.str.val = estrndup(yytext+bprefix+1, yyleng-bprefix-2); + zendlval->value.str.len = yyleng-bprefix-2; + zendlval->type = IS_STRING; + + /* convert escape sequences */ + s = t = zendlval->value.str.val; + end = s+zendlval->value.str.len; + while (s<end) { + if (*s=='\\') { + s++; + + switch(*s) { + case '\\': + case '\'': + *t++ = *s; + zendlval->value.str.len--; + break; + default: + *t++ = '\\'; + *t++ = *s; + break; + } + } else { + *t++ = *s; + } + + if (*s == '\n' || (*s == '\r' && (*(s+1) != '\n'))) { + CG(zend_lineno)++; + } + s++; + } + *t = 0; + + if (SCNG(output_filter)) { + size_t sz = 0; + s = zendlval->value.str.val; + SCNG(output_filter)((unsigned char **)&(zendlval->value.str.val), &sz, (unsigned char *)s, (size_t)zendlval->value.str.len TSRMLS_CC); + zendlval->value.str.len = sz; + efree(s); + } + return T_CONSTANT_ENCAPSED_STRING; +} + + +<ST_IN_SCRIPTING>b?["] { + int bprefix = (yytext[0] != '"') ? 1 : 0; + + while (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR++) { + case '"': + yyleng = YYCURSOR - SCNG(yy_text); + zend_scan_escape_string(zendlval, yytext+bprefix+1, yyleng-bprefix-2, '"' TSRMLS_CC); + return T_CONSTANT_ENCAPSED_STRING; + case '$': + if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') { + break; + } + continue; + case '{': + if (*YYCURSOR == '$') { + break; + } + continue; + case '\\': + if (YYCURSOR < YYLIMIT) { + YYCURSOR++; + } + /* fall through */ + default: + continue; + } + + YYCURSOR--; + break; + } + + /* Remember how much was scanned to save rescanning */ + SET_DOUBLE_QUOTES_SCANNED_LENGTH(YYCURSOR - SCNG(yy_text) - yyleng); + + YYCURSOR = SCNG(yy_text) + yyleng; + + BEGIN(ST_DOUBLE_QUOTES); + return '"'; +} + + +<ST_IN_SCRIPTING>b?"<<<"{TABS_AND_SPACES}({LABEL}|([']{LABEL}['])|(["]{LABEL}["])){NEWLINE} { + char *s; + int bprefix = (yytext[0] != '<') ? 1 : 0; + + /* save old heredoc label */ + Z_STRVAL_P(zendlval) = CG(heredoc); + Z_STRLEN_P(zendlval) = CG(heredoc_len); + + CG(zend_lineno)++; + CG(heredoc_len) = yyleng-bprefix-3-1-(yytext[yyleng-2]=='\r'?1:0); + s = yytext+bprefix+3; + while ((*s == ' ') || (*s == '\t')) { + s++; + CG(heredoc_len)--; + } + + if (*s == '\'') { + s++; + CG(heredoc_len) -= 2; + + BEGIN(ST_NOWDOC); + } else { + if (*s == '"') { + s++; + CG(heredoc_len) -= 2; + } + + BEGIN(ST_HEREDOC); + } + + CG(heredoc) = estrndup(s, CG(heredoc_len)); + + /* Check for ending label on the next line */ + if (CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, s, CG(heredoc_len))) { + YYCTYPE *end = YYCURSOR + CG(heredoc_len); + + if (*end == ';') { + end++; + } + + if (*end == '\n' || *end == '\r') { + BEGIN(ST_END_HEREDOC); + } + } + + return T_START_HEREDOC; +} + + +<ST_IN_SCRIPTING>[`] { + BEGIN(ST_BACKQUOTE); + return '`'; +} + + +<ST_END_HEREDOC>{ANY_CHAR} { + YYCURSOR += CG(heredoc_len) - 1; + yyleng = CG(heredoc_len); + + Z_STRVAL_P(zendlval) = CG(heredoc); + Z_STRLEN_P(zendlval) = CG(heredoc_len); + CG(heredoc) = NULL; + CG(heredoc_len) = 0; + BEGIN(ST_IN_SCRIPTING); + return T_END_HEREDOC; +} + + +<ST_DOUBLE_QUOTES,ST_BACKQUOTE,ST_HEREDOC>"{$" { + zendlval->value.lval = (long) '{'; + yy_push_state(ST_IN_SCRIPTING TSRMLS_CC); + yyless(1); + return T_CURLY_OPEN; +} + + +<ST_DOUBLE_QUOTES>["] { + BEGIN(ST_IN_SCRIPTING); + return '"'; +} + +<ST_BACKQUOTE>[`] { + BEGIN(ST_IN_SCRIPTING); + return '`'; +} + + +<ST_DOUBLE_QUOTES>{ANY_CHAR} { + if (GET_DOUBLE_QUOTES_SCANNED_LENGTH()) { + YYCURSOR += GET_DOUBLE_QUOTES_SCANNED_LENGTH() - 1; + SET_DOUBLE_QUOTES_SCANNED_LENGTH(0); + + goto double_quotes_scan_done; + } + + if (YYCURSOR > YYLIMIT) { + return 0; + } + if (yytext[0] == '\\' && YYCURSOR < YYLIMIT) { + YYCURSOR++; + } + + while (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR++) { + case '"': + break; + case '$': + if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') { + break; + } + continue; + case '{': + if (*YYCURSOR == '$') { + break; + } + continue; + case '\\': + if (YYCURSOR < YYLIMIT) { + YYCURSOR++; + } + /* fall through */ + default: + continue; + } + + YYCURSOR--; + break; + } + +double_quotes_scan_done: + yyleng = YYCURSOR - SCNG(yy_text); + + zend_scan_escape_string(zendlval, yytext, yyleng, '"' TSRMLS_CC); + return T_ENCAPSED_AND_WHITESPACE; +} + + +<ST_BACKQUOTE>{ANY_CHAR} { + if (YYCURSOR > YYLIMIT) { + return 0; + } + if (yytext[0] == '\\' && YYCURSOR < YYLIMIT) { + YYCURSOR++; + } + + while (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR++) { + case '`': + break; + case '$': + if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') { + break; + } + continue; + case '{': + if (*YYCURSOR == '$') { + break; + } + continue; + case '\\': + if (YYCURSOR < YYLIMIT) { + YYCURSOR++; + } + /* fall through */ + default: + continue; + } + + YYCURSOR--; + break; + } + + yyleng = YYCURSOR - SCNG(yy_text); + + zend_scan_escape_string(zendlval, yytext, yyleng, '`' TSRMLS_CC); + return T_ENCAPSED_AND_WHITESPACE; +} + + +<ST_HEREDOC>{ANY_CHAR} { + int newline = 0; + + if (YYCURSOR > YYLIMIT) { + return 0; + } + + YYCURSOR--; + + while (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR++) { + case '\r': + if (*YYCURSOR == '\n') { + YYCURSOR++; + } + /* fall through */ + case '\n': + /* Check for ending label on the next line */ + if (IS_LABEL_START(*YYCURSOR) && CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, CG(heredoc), CG(heredoc_len))) { + YYCTYPE *end = YYCURSOR + CG(heredoc_len); + + if (*end == ';') { + end++; + } + + if (*end == '\n' || *end == '\r') { + /* newline before label will be subtracted from returned text, but + * yyleng/yytext will include it, for zend_highlight/strip, tokenizer, etc. */ + if (YYCURSOR[-2] == '\r' && YYCURSOR[-1] == '\n') { + newline = 2; /* Windows newline */ + } else { + newline = 1; + } + + CG(increment_lineno) = 1; /* For newline before label */ + BEGIN(ST_END_HEREDOC); + + goto heredoc_scan_done; + } + } + continue; + case '$': + if (IS_LABEL_START(*YYCURSOR) || *YYCURSOR == '{') { + break; + } + continue; + case '{': + if (*YYCURSOR == '$') { + break; + } + continue; + case '\\': + if (YYCURSOR < YYLIMIT && *YYCURSOR != '\n' && *YYCURSOR != '\r') { + YYCURSOR++; + } + /* fall through */ + default: + continue; + } + + YYCURSOR--; + break; + } + +heredoc_scan_done: + yyleng = YYCURSOR - SCNG(yy_text); + + zend_scan_escape_string(zendlval, yytext, yyleng - newline, 0 TSRMLS_CC); + return T_ENCAPSED_AND_WHITESPACE; +} + + +<ST_NOWDOC>{ANY_CHAR} { + int newline = 0; + + if (YYCURSOR > YYLIMIT) { + return 0; + } + + YYCURSOR--; + + while (YYCURSOR < YYLIMIT) { + switch (*YYCURSOR++) { + case '\r': + if (*YYCURSOR == '\n') { + YYCURSOR++; + } + /* fall through */ + case '\n': + /* Check for ending label on the next line */ + if (IS_LABEL_START(*YYCURSOR) && CG(heredoc_len) < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, CG(heredoc), CG(heredoc_len))) { + YYCTYPE *end = YYCURSOR + CG(heredoc_len); + + if (*end == ';') { + end++; + } + + if (*end == '\n' || *end == '\r') { + /* newline before label will be subtracted from returned text, but + * yyleng/yytext will include it, for zend_highlight/strip, tokenizer, etc. */ + if (YYCURSOR[-2] == '\r' && YYCURSOR[-1] == '\n') { + newline = 2; /* Windows newline */ + } else { + newline = 1; + } + + CG(increment_lineno) = 1; /* For newline before label */ + BEGIN(ST_END_HEREDOC); + + goto nowdoc_scan_done; + } + } + /* fall through */ + default: + continue; + } + } + +nowdoc_scan_done: + yyleng = YYCURSOR - SCNG(yy_text); + + zend_copy_value(zendlval, yytext, yyleng - newline); + zendlval->type = IS_STRING; + HANDLE_NEWLINES(yytext, yyleng - newline); + return T_ENCAPSED_AND_WHITESPACE; +} + + +<ST_IN_SCRIPTING,ST_VAR_OFFSET>{ANY_CHAR} { + if (YYCURSOR > YYLIMIT) { + return 0; + } + + zend_error(E_COMPILE_WARNING,"Unexpected character in input: '%c' (ASCII=%d) state=%d", yytext[0], yytext[0], YYSTATE); + goto restart; +} + +*/ +} diff --git a/recherches/parsers/lime.tar.gz b/recherches/parsers/lime.tar.gz Binary files differnew file mode 100644 index 0000000..f3f8f89 --- /dev/null +++ b/recherches/parsers/lime.tar.gz diff --git a/recherches/parsers/nikic-PHP-Parser-v0.9.2.txt b/recherches/parsers/nikic-PHP-Parser-v0.9.2.txt new file mode 100644 index 0000000..016af6f --- /dev/null +++ b/recherches/parsers/nikic-PHP-Parser-v0.9.2.txt @@ -0,0 +1 @@ +https://github.com/nikic/PHP-Parser diff --git a/tests/test01-parsing/src/composer.json b/tests/test01-parsing/src/composer.json new file mode 100644 index 0000000..a366739 --- /dev/null +++ b/tests/test01-parsing/src/composer.json @@ -0,0 +1,6 @@ +{ + "require": { + "nikic/php-parser": "0.9.2" + } +} + diff --git a/tests/test01-parsing/src/get_deps.sh b/tests/test01-parsing/src/get_deps.sh new file mode 100755 index 0000000..67c84c3 --- /dev/null +++ b/tests/test01-parsing/src/get_deps.sh @@ -0,0 +1,2 @@ +#!/bin/sh +php ../../../composer.phar install diff --git a/tests/test01-parsing/src/php-weave/main.php b/tests/test01-parsing/src/php-weave/main.php new file mode 100644 index 0000000..2a4df55 --- /dev/null +++ b/tests/test01-parsing/src/php-weave/main.php @@ -0,0 +1,64 @@ +<?php +require '../vendor/nikic/php-parser/lib/bootstrap.php'; +require './visitors.inc.php'; + +ini_set('xdebug.max_nesting_level', 2000); + +function dbg($indent, $text) { + for($i=0;$i<$indent;$i++) echo "."; + echo "$text\n"; +} + +function recursive_parse($src_filepath, $stmts1_filepath, $stmts2_filepath, $level=0) { + global $parser,$nodeDumper; + + try { + dbg($level,"Parsing '$src_filepath'"); + $stmts = $parser->parse(file_get_contents($src_filepath)); + + if (strlen($stmts1_filepath) > 0 ) { + dbg($level,"Dumping1 '$src_filepath' AST to '$stmts1_filepath'"); + file_put_contents($stmts1_filepath, $nodeDumper->dump($stmts)); + } + + dbg($level,"Transforming '$src_filepath'"); + $traverser = new PHPParser_NodeTraverser; +/* + $traverser->addVisitor(new PHPParser_NodeVisitor_NameResolver); + $traverser->addVisitor(new NodeVisitor_NamespaceConverter); +*/ + // FIXME : getcwd is quick and dirty here + $traverser->addVisitor(new NodeVisitor_PreprocessInclude($level, getcwd(), $src_filepath)); + $stmts = $traverser->traverse($stmts); + $traverser=null; //Destroy + + if (strlen($stmts2_filepath) > 0) { + dbg($level,"Dumping2 '$src_filepath' AST to '$stmts2_filepath'"); + file_put_contents($stmts2_filepath, $nodeDumper->dump($stmts)); + } + + } catch (PHPParser_Error $e) { + echo 'Parse Error: ', $e->getMessage(); + } + return $stmts; +} + + +// Main +$src_filepath = "./main.php"; +#$src_filepath = "./to_parse.php"; +$stmts1_filepath = "out/stmts1.ast"; +$stmts2_filepath = "out/stmts2.ast"; +$dest_filepath = "out/result.php"; + +$parser = new PHPParser_Parser(new PHPParser_Lexer); +$nodeDumper = new PHPParser_NodeDumper; + +$level=0; +$stmts=recursive_parse($src_filepath, $stmts1_filepath, $stmts2_filepath); + +dbg(0,"Outputing '$dest_filepath'"); +$prettyPrinter = new PHPParser_PrettyPrinter_Zend; +file_put_contents($dest_filepath, "<?php\n" . $prettyPrinter->prettyPrint($stmts) . "\n?>"); + +?> diff --git a/tests/test01-parsing/src/php-weave/to_parse.php b/tests/test01-parsing/src/php-weave/to_parse.php new file mode 100644 index 0000000..7b953d5 --- /dev/null +++ b/tests/test01-parsing/src/php-weave/to_parse.php @@ -0,0 +1,5 @@ +<?php +if (1){ +include('./inc.php'); +} +?> diff --git a/tests/test01-parsing/src/php-weave/visitors.inc.php b/tests/test01-parsing/src/php-weave/visitors.inc.php new file mode 100644 index 0000000..3f997ad --- /dev/null +++ b/tests/test01-parsing/src/php-weave/visitors.inc.php @@ -0,0 +1,91 @@ +<?php +/* +class NodeVisitor_NamespaceConverter extends PHPParser_NodeVisitorAbstract +{ + public function leaveNode(PHPParser_Node $node) { + if ($node instanceof PHPParser_Node_Name) { + return new PHPParser_Node_Name($node->toString('_')); + } elseif ($node instanceof PHPParser_Node_Stmt_Class + || $node instanceof PHPParser_Node_Stmt_Interface + || $node instanceof PHPParser_Node_Stmt_Function) { + $node->name = $node->namespacedName->toString('_'); + } elseif ($node instanceof PHPParser_Node_Stmt_Const) { + foreach ($node->consts as $const) { + $const->name = $const->namespacedName->toString('_'); + } + } elseif ($node instanceof PHPParser_Node_Stmt_Namespace) { + // returning an array merges is into the parent array + return $node->stmts; + } elseif ($node instanceof PHPParser_Node_Stmt_Use) { + // returning false removed the node altogether + return false; + } + } +} +*/ + +class NodeVisitor_PreprocessInclude extends PHPParser_NodeVisitorAbstract { + protected $level; + protected $cwd; + protected $filepath; + protected $prettyPrinter; + + public function __construct($level, $cwd, $filepath) { + $this->level=$level; + $this->cwd=$cwd; + $this->filepath=$filepath; + $this->prettyPrinter = new PHPParser_PrettyPrinter_Zend; + } + + protected function resolveIncludePath($node) { + //FIXME : Quick and dirty + // no classpath checks... + // no check if compound value like "dirname(__FILE__) . '/PHPParser/Autoloader.php'" + return $node->expr->value; + } + + public function enterNode(PHPParser_Node $node) { + if ($node instanceof PHPParser_Node_Expr_Include) { + // Already processed, go out (occurs if an unresolved include has left as is in the previous recursion level) + if (is_array($node->attributes) && array_key_exists('NodeVisitor_PreprocessInclude', $node->attributes)) return $node; + + switch($node->type) { + case PHPParser_Node_Expr_Include::TYPE_INCLUDE: + case PHPParser_Node_Expr_Include::TYPE_REQUIRE: + $once=0; + break; + case PHPParser_Node_Expr_Include::TYPE_INCLUDE_ONCE: + case PHPParser_Node_Expr_Include::TYPE_REQUIRE_ONCE: + $once=1; + echo "TODO : include_once or require_once\n"; + break; + default: + echo "FIXME : BUG NodeVisitor_PreprocessInclude::enterNode !!\n"; + return $node; + } + + $path=$this->resolveIncludePath($node); + + //FIXME : No infinite recursion check like test.php contains include('./test.php'); + // Preprocess include if readable + $comment_suffix=" */"; + if ( ($this->level < 3) && is_readable($path)) { + $comment_prefix="/* "; + //FIXME : use a closure or sort of here (dependancy injection) + //$stmts=recursive_parse($path, "out/rec.out1", "out/rec.out2", $this->level+1); + $stmts=recursive_parse($path, "", "", $this->level+1); + } else { + $comment_prefix="/* UNRESOLVED : "; + $node->attributes['NodeVisitor_PreprocessInclude']='unresolved'; + $stmts=array($node); // Caution : can cause infinite loop (will be tried at the next step) + } + + $comment= new PHPParser_Comment($comment_prefix . $this->prettyPrinter->prettyPrint(array($node)) . $comment_suffix); + + // FIXME : Get out this if() that is a trick for not returning here an array instead of a node + return new PHPParser_Node_Stmt_If(new PHPParser_Node_Scalar_LNumber(1),array('stmts'=>$stmts),array('comments'=>array($comment))); + } + + } +} + |