// simple Bison grammar file to add braces in php code to // the single-statements under if, while, for // Arnia Software, address@hidden %code requires { #include #include #include #undef YYSTYPE #define YYSTYPE std::string } // generate a C++ parser from the grammar %skeleton "lalr1.cc" %require "2.4.1" // tokens used in the gramar (returned from scanner) %token T_END 0 "end of file" %token T_INLINE_HTML %token T_OPEN_TAG %token T_OPEN_TAG_WITH_ECHO %token T_PLAIN_NAME %token T_PAAMAYIM_NEKUDOTAYIM %token T_CLOSE_TAG %token T_IF %token T_ELSEIF %token T_ELSE %token T_SWITCH %token T_CASE %token T_BREAK %token T_CONTINUE %token T_DEFAULT %token T_GOTO %token T_FOR %token T_AS %token T_FOREACH %token T_WHILE %token T_DO %token T_WHITESPACE %token T_INCLUDE %token T_INCLUDE_ONCE %token T_REQUIRE %token T_REQUIRE_ONCE %token T_COMMENT %token T_CLASS %token T_INTERFACE %token T_TRAIT %token T_EXTENDS %token T_IMPLEMENTS %token T_FINAL %token T_FUNCTION %token T_VAR %token T_PUBLIC %token T_PRIVATE %token T_STATIC %token T_CONST %token T_OBJECT_OPERATOR %token T_RETURN %token T_GLOBAL %token T_NEW %token T_THROW %token T_TRY %token T_CATCH %token T_PRINT %token T_ECHO %token T_CLONE %token T_USE %token T_INSTANCEOF %token T_LOGICAL_AND %token T_LOGICAL_OR %token T_LOGICAL_XOR %token T_LNUMBER "integral number" %token T_DNUMBER "real number" %token T_STRING %token T_VARIABLE %token T_DOUBLE_ARROW %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)" %token T_BOOLEAN_OR %token T_BOOLEAN_AND %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)" %token T_IS_SMALLER_OR_EQUAL "<= (T_IS_SMALLER_OR_EQUAL)" %token T_IS_GREATER_OR_EQUAL ">= (T_IS_GREATER_OR_EQUAL)" %token T_SR ">> (T_SR)" %token T_SL "<< (T_SL)" %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)" %start php_script %defines %define parser_class_name "phpParser" %parse-param { class phpLexer &lexer } %parse-param { std::ostream &outstream } %parse-param { std::string const &input_filename } %lex-param { phpLexer &lexer } %locations %code { // include tokenizer class #include "phpFlexLexer.hh" using namespace std; // global yylex function, that will invoke yylex() method on the // phpLexer object inline yy::phpParser::token_type yylex ( yy::phpParser::semantic_type *yylval, yy::phpParser::location_type *yylloc, yy::phpLexer &lexer ) { lexer.yylval = yylval; lexer.yylloc = yylloc; return static_cast(lexer.yylex()); } } // %initial-action // { // // Initialize filename for location // if (!input_filename.emtpy()) // @$.begin.filename = @$.end.filename = input_filename; // } %% // // php comments, whitespace // // note that this parser preserves whitespace and comments // t_comment_or_whitespace: T_WHITESPACE | T_COMMENT ; plain_comment_or_whitespace: t_comment_or_whitespace | plain_comment_or_whitespace t_comment_or_whitespace { $$ = $1 + $2; } ; // optional comments and whitespaces t_comment_or_whitespaces: /* empty */ { $$ = ""; } | plain_comment_or_whitespace ; // // literals, identifiers, variables // literal_value: T_STRING | T_LNUMBER | T_DNUMBER /* NULL, FALSE and TRUE will just be treated as plain names (identifiers or constants) in this grammer */ ; variable_variable: '$' '{' t_comment_or_whitespaces expr t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; } ; name_or_variable: variable_variable | /* name expression or constructed name (usually from a string literal) */ '{' t_comment_or_whitespaces expr t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } | T_VARIABLE | T_PLAIN_NAME ; qualified_name_expr: /* scope resolution */ name_or_variable | qualified_name_expr t_comment_or_whitespaces T_PAAMAYIM_NEKUDOTAYIM t_comment_or_whitespaces name_or_variable { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; // // operators, expressions // property_declaration: qualified_name_expr t_comment_or_whitespaces ':' t_comment_or_whitespaces expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; property_declaration_seq: property_declaration | property_declaration_seq t_comment_or_whitespaces ',' t_comment_or_whitespaces property_declaration { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; object_constructor: '{' t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; } | '{' t_comment_or_whitespaces property_declaration_seq t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; primary_expr: literal_value | qualified_name_expr | object_constructor | '(' t_comment_or_whitespaces expr t_comment_or_whitespaces ')' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; postfix_expr: primary_expr | /* member-access expression */ postfix_expr t_comment_or_whitespaces T_OBJECT_OPERATOR primary_expr { $$ = $1 + $2; $$ += $3; $$ += $4; } | /* postfix increment */ postfix_expr t_comment_or_whitespaces T_INC { $$ = $1 + $2; $$ += $3; } | /* postfix decrement */ postfix_expr t_comment_or_whitespaces T_DEC { $$ = $1 + $2; $$ += $3; } | /* function call expression */ postfix_expr t_comment_or_whitespaces '(' t_comment_or_whitespaces expr_list t_comment_or_whitespaces ')' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; } | /* array subscript expression */ postfix_expr t_comment_or_whitespaces '[' t_comment_or_whitespaces expr t_comment_or_whitespaces ']' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; } | /* string subscript expression */ postfix_expr t_comment_or_whitespaces '{' t_comment_or_whitespaces expr t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; } ; cast_operator: T_INT_CAST | T_DOUBLE_CAST | T_STRING_CAST | T_ARRAY_CAST | T_OBJECT_CAST | T_BOOL_CAST | T_UNSET_CAST ; /* chain expression, normally a subset of postfix-expression, but needed separately for the following T_CLONE expr */ chain_expr: primary_expr | chain_expr t_comment_or_whitespaces T_OBJECT_OPERATOR t_comment_or_whitespaces primary_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; /* prefix expressions */ unary_expr: postfix_expr | /* new expression */ T_NEW t_comment_or_whitespaces name_or_variable t_comment_or_whitespaces '(' t_comment_or_whitespaces expr_list t_comment_or_whitespaces ')' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; } | /* clone expression, php manual says clone has a hight precedence, which would be a little strange for an unary expr */ T_CLONE t_comment_or_whitespaces chain_expr { $$ = $1 + $2; $$ += $3; } | '-' t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | '+' t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | '~' t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | '@' t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | '&' t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | T_INC t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | T_DEC t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } | cast_operator t_comment_or_whitespaces postfix_expr { $$ = $1 + $2; $$ += $3; } ; /* php manual has instanceof on its own priority level */ instanceof_expr: unary_expr | unary_expr t_comment_or_whitespaces T_INSTANCEOF t_comment_or_whitespaces qualified_name_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; logical_not_expr: instanceof_expr | '!' t_comment_or_whitespaces logical_not_expr { $$ = $1 + $2; $$ += $3; } ; multiplicative_op: '*' | '/' | '%' ; multiplicative_expr: logical_not_expr | multiplicative_expr t_comment_or_whitespaces multiplicative_op t_comment_or_whitespaces logical_not_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; additive_op: '+' | '-' | '.' ; additive_expr: multiplicative_expr | additive_expr t_comment_or_whitespaces additive_op t_comment_or_whitespaces multiplicative_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; bitwise_shift_op: T_SL | T_SR ; bitwise_shift_expr: additive_expr | bitwise_shift_expr t_comment_or_whitespaces bitwise_shift_op t_comment_or_whitespaces additive_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; relational_op: '<' | T_IS_SMALLER_OR_EQUAL | T_IS_EQUAL | T_IS_IDENTICAL | T_IS_NOT_IDENTICAL | T_IS_NOT_EQUAL | T_IS_GREATER_OR_EQUAL | '>' ; relational_expr: bitwise_shift_expr | relational_expr t_comment_or_whitespaces relational_op t_comment_or_whitespaces bitwise_shift_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; bitwise_and_expr: relational_expr | bitwise_and_expr t_comment_or_whitespaces '&' t_comment_or_whitespaces relational_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; bitwise_xor_expr: bitwise_and_expr | bitwise_xor_expr t_comment_or_whitespaces '^' t_comment_or_whitespaces bitwise_and_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; bitwise_or_expr: bitwise_xor_expr | bitwise_or_expr t_comment_or_whitespaces '|' t_comment_or_whitespaces bitwise_xor_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; boolean_and_expr: bitwise_or_expr | boolean_and_expr t_comment_or_whitespaces T_BOOLEAN_AND t_comment_or_whitespaces bitwise_or_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; boolean_or_expr: boolean_and_expr | boolean_or_expr t_comment_or_whitespaces T_BOOLEAN_OR t_comment_or_whitespaces boolean_and_expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; conditional_expression: boolean_or_expr | conditional_expression '?' conditional_expression ':' conditional_expression { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; assignament_operator: '=' | T_PLUS_EQUAL | T_MINUS_EQUAL | T_CONCAT_EQUAL | T_MUL_EQUAL | T_DIV_EQUAL | T_MOD_EQUAL | T_AND_EQUAL | T_OR_EQUAL | T_XOR_EQUAL | T_SL_EQUAL | T_SR_EQUAL ; assignament_expression: conditional_expression | conditional_expression t_comment_or_whitespaces assignament_operator t_comment_or_whitespaces assignament_expression { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; logical_and_expression: assignament_expression | logical_and_expression t_comment_or_whitespaces T_LOGICAL_AND t_comment_or_whitespaces assignament_expression { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; logical_xor_expression: logical_and_expression | logical_xor_expression t_comment_or_whitespaces T_LOGICAL_XOR t_comment_or_whitespaces logical_and_expression { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; logical_or_expression: logical_xor_expression | logical_or_expression t_comment_or_whitespaces T_LOGICAL_OR t_comment_or_whitespaces logical_xor_expression { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; /* only used for array population and iteration */ array_key_val_expression: logical_or_expression | logical_or_expression t_comment_or_whitespaces T_DOUBLE_ARROW t_comment_or_whitespaces logical_or_expression { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; expr: array_key_val_expression ; plain_expr_list: expr | plain_expr_list t_comment_or_whitespaces ',' t_comment_or_whitespaces expr { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; expr_list: /* empty */ { $$ = ""; } | plain_expr_list ; // // php statements // decl_spec: T_GLOBAL | T_VAR | T_PUBLIC | T_PRIVATE | T_STATIC | T_CONST ; plain_decl_spec_seq: decl_spec | decl_spec_seq t_comment_or_whitespaces decl_spec { $$ = $1 + $2; $$ += $3; } ; decl_spec_seq: /* empty */ { $$ = ""; } | plain_decl_spec_seq ; plain_statement_delimiter: ';' | T_CLOSE_TAG ; statement_delimiter: t_comment_or_whitespaces plain_statement_delimiter { $$ = $1 + $2; } ; empty_statement: statement_delimiter ; block_statement: '{' statement_seq t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; $$ += $4; } | '{' t_comment_or_whitespaces '}' { $$ = $1 + $2; $$ += $3; } ; expr_statement: expr statement_delimiter { $$ = $1 + $2; } ; decl_statement: plain_decl_spec_seq t_comment_or_whitespaces expr_statement { $$ = $1 + $2; $$ += $3; } ; command_statement_name: T_RETURN | T_PRINT | T_ECHO | T_INCLUDE | T_INCLUDE_ONCE | T_REQUIRE | T_REQUIRE_ONCE | T_THROW | T_USE ; command_statement: command_statement_name t_comment_or_whitespaces expr statement_delimiter { $$ = $1 + $2; $$ += $3; $$ += $4; } ; // if statement if_branch: T_IF t_comment_or_whitespaces '(' t_comment_or_whitespaces expr t_comment_or_whitespaces ')' t_comment_or_whitespaces statement { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; } elseif_branch: t_comment_or_whitespaces T_ELSEIF t_comment_or_whitespaces statement { $$ = $1 + $2; $$ += $3; $$ += $4; } plain_elseif_seq: elseif_branch | plain_elseif_seq elseif_branch { $$ = $1 + $2; } ; elseif_seq: /* empty */ { $$ = ""; } | plain_elseif_seq ; else_branch: t_comment_or_whitespaces T_ELSE t_comment_or_whitespaces statement { $$ = $1 + $2; $$ += $3; $$ += $4; } ; if_statement: if_branch elseif_seq { $$ = $1 + $2; } | if_branch elseif_seq else_branch { $$ = $1 + $2; $$ += $3; } ; // switch statement case_statement: T_CASE t_comment_or_whitespaces expr t_comment_or_whitespaces ':' { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; default_statetement: T_DEFAULT t_comment_or_whitespaces ':' { $$ = $1 + $2; $$ += $3; } ; break_statement: T_BREAK statement_delimiter { $$ = $1 + $2; } ; continue_statement: T_CONTINUE statement_delimiter { $$ = $1 + $2; } ; switch_statement: T_SWITCH t_comment_or_whitespaces '(' t_comment_or_whitespaces expr t_comment_or_whitespaces ')' t_comment_or_whitespaces statement { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; } ; // goto statement label_statement: expr t_comment_or_whitespaces ':' { $$ = $1 + $2; $$ += $3; } ; goto_statement: T_GOTO t_comment_or_whitespaces expr statement_delimiter { $$ = $1 + $2; $$ += $3; $$ += $4; } ; // for statement for_statement: T_FOR t_comment_or_whitespaces '(' t_comment_or_whitespaces expr_statement t_comment_or_whitespaces expr_statement t_comment_or_whitespaces expr_statement t_comment_or_whitespaces ')' t_comment_or_whitespaces statement { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() + $7.length() + $8.length() + $9.length() + $10.length() + $11.length() + $12.length() + $13.length() ); $$ = $1 + $2; $$ += $3; $$ += $4 $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; $$ += $10; $$ += $11; $$ += $12; $$ += $13; } ; // foreach statement foreach_statement: T_FOREACH t_comment_or_whitespaces '(' t_comment_or_whitespaces expr t_comment_or_whitespaces T_AS t_comment_or_whitespaces expr t_comment_or_whitespaces ')' t_comment_or_whitespaces statement { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() + $7.length() + $8.length() + $9.length() + $10.length() + $11.length() + $12.length() + $13.length() ); $$ = $1 + $2; $$ += $3; $$ += $4 $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; $$ += $10; $$ += $11; $$ += $12; $$ += $13; } ; // while statement while_statement: T_WHILE t_comment_or_whitespaces '(' t_comment_or_whitespaces expr t_comment_or_whitespaces ')' t_comment_or_whitespaces statement { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() + $7.length() + $8.length() + $9.length() ); $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; } // do-while statement do_while_statement: T_DO t_comment_or_whitespaces statement T_WHILE t_comment_or_whitespaces '(' t_comment_or_whitespaces expr t_comment_or_whitespaces ')' statement_delimiter { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() + $7.length() + $8.length() + $9.length() + $10.length() + $11.length() ); $$ = $1 + $2; $$ += $3; $$ += $4 $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; $$ += $10; $$ += $11; } ; // try-catch statement catch_clause: T_CATCH t_comment_or_whitespaces '(' t_comment_or_whitespaces qualified_name_expr t_comment_or_whitespaces name_or_variable t_comment_or_whitespaces ')' t_comment_or_whitespaces block_statement { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() + $7.length() + $8.length() + $9.length() + $10.length() + $11.length() ); $$ = $1 + $2; $$ += $3; $$ += $4 $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; $$ += $10; $$ += $11; } ; catch_clause_seq: catch_clause | catch_clause_seq t_comment_or_whitespaces catch_clause { $$ = $1 + $2; $$ += $3; } ; try_statement: T_TRY t_comment_or_whitespaces block_statement t_comment_or_whitespaces catch_clause_seq { $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } // function declaration and defintion function_body_or_semicolon: t_comment_or_whitespaces block_statement { $$ = $1 + $2; } | statement_delimiter ; function_decl_statement: decl_spec_seq t_comment_or_whitespaces T_FUNCTION t_comment_or_whitespaces qualified_name_expr t_comment_or_whitespaces '(' t_comment_or_whitespaces expr_list t_comment_or_whitespaces t_comment_or_whitespaces ')' function_body_or_semicolon { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() + $7.length() + $8.length() + $9.length() + $10.length() + $11.length() + $12.length() + $13.length() ); $$ = $1 + $2; $$ += $3; $$ += $4 $$ += $5; $$ += $6; $$ += $7; $$ += $8; $$ += $9; $$ += $10; $$ += $11; $$ += $12; $$ += $13; } // classes class_key: T_INTERFACE | T_TRAIT | T_CLASS | T_FINAL t_comment_or_whitespaces T_CLASS { $$ = $1 + $2; $$ += $3; } | T_FINAL t_comment_or_whitespaces T_INTERFACE { $$ = $1 + $2; $$ += $3; } ; class_inheritance_key: T_EXTENDS | T_IMPLEMENTS ; base_class_decl: class_inheritance_key t_comment_or_whitespaces qualified_name_expr { $$ = $1 + $2; $$ += $3; } base_class_decl_seq: base_class_decl | base_class_decl_seq t_comment_or_whitespaces base_class_decl { $$ = $1 + $2; $$ += $3; } ; base_classes_list: /* empty */ { $$ = ""; } | t_comment_or_whitespaces base_class_decl_seq { $$ = $1 + $2; } ; class_declaration: class_key t_comment_or_whitespaces qualified_name_expr base_classes_list t_comment_or_whitespaces block_statement { $$.reserve ( $1.length() + $2.length() + $3.length() + $4.length() + $5.length() + $6.length() ); $$ = $1 + $2; $$ += $3; $$ += $4; $$ += $5; } ; statement: T_INLINE_HTML | T_OPEN_TAG | T_OPEN_TAG_WITH_ECHO | empty_statement | block_statement | decl_statement | expr_statement | command_statement | if_statement | case_statement | default_statetement | break_statement | continue_statement | label_statement | goto_statement | switch_statement | for_statement | foreach_statement | while_statement | do_while_statement | try_statement | function_decl_statement | class_declaration ; statement_seq: t_comment_or_whitespaces statement { $$ = $1 + $2; } | statement_seq t_comment_or_whitespaces statement { $$ = $1 + $2; $$ += $3; } ; plain_php_script: t_comment_or_whitespaces statement { outstream << $1 << $2; } | plain_php_script t_comment_or_whitespace statement { outstream << $2 << $3; } ; php_script: /* empty */ | plain_php_script t_comment_or_whitespaces { outstream << $2; } ; %% void yy::phpParser::error ( yy::phpParser::location_type const &l, std::string const &m ) { cerr << l.end << ": " << m << "." << endl; }