Warning, /kdevelop/kdev-php/parser/php.g is written in an unsupported language. File is not indexed.
0001 ------------------------------------------------------------------------------- 0002 -- SPDX-FileCopyrightText: 2008 Niko Sams <niko.sams@gmail.com> 0003 -- 0004 -- SPDX-License-Identifier: LGPL-2.0-or-later 0005 ----------------------------------------------------------- 0006 0007 0008 ----------------------------------------------------------- 0009 -- Grammar for PHP 5.2 0010 -- Modelled after the Zend Grammar shipped with PHP5.2 0011 -- source, the PHP Language Reference documentation, 0012 -- and parts taken from KDevelop Java Grammar 0013 ----------------------------------------------------------- 0014 0015 -- 4 first/first conflicts: 0016 -- - var_expression: variable vs. varExpressionNormal 0017 -- no problem because of ifs that allow always just one rule 0018 -- - classNameReference: STRING vs. staticMember (foo vs. foo::$bar) 0019 -- resolved by LA() 0020 -- - encapsVar: STRING_VARNAME LBRACKET vs. expr (expr allows STRING_VARNAME too - but not LBRACKET) 0021 -- resolved by LA() 0022 -- - constantOrClassConst: constant vs. class constant (FOO v.s Cls::FOO) 0023 -- resolved by LA() (could be avoided, but the Ast is much cleaner that way) 0024 -- 1 first/follow conflicts: 0025 -- - elseifList: dangling-else conflict - should be ok 0026 0027 -- TODO: (post 1.0.0 release) 0028 -- 1) decrease memory consumption 0029 -- 1.1) use quint32 instead of qint64 for end/start tokens 0030 -- 1.2) investigate whether using a map/hash for the ducontext member of all 0031 -- ast nodes gives a significant memory decrease while not hampering performance 0032 -- 1.3) investigate how unions could be used for exclusive AST node members 0033 -- 1.4) see whether we can always use the expression lists instead of both 0034 -- single member pointer and list of members, esp. in expressions 0035 -- 2) better cope with invalid code, have at least a partial AST 0036 -- 3) investigate whether expanding the visitor lookup to a 0037 -- (albeit huge) switch() in KDev-PG-Qt gives a significant performance gain 0038 -- I have the gut feeling that the current lookup takes unnecessary much time 0039 -- 0040 0041 ------------------------------------------------------------ 0042 -- Forward declaration in phpast.h 0043 ------------------------------------------------------------ 0044 0045 [: 0046 0047 #include <QtCore/QRegularExpression> 0048 0049 namespace KDevelop 0050 { 0051 class DUContext; 0052 } 0053 0054 :] 0055 0056 ------------------------------------------------------------ 0057 -- Additional includes for the parser 0058 ------------------------------------------------------------ 0059 0060 %parser_declaration_header "parser/tokenstream.h" 0061 %parser_declaration_header "QtCore/QString" 0062 %parser_declaration_header "language/duchain/problem.h" 0063 %parser_declaration_header "parser/phplexer.h" 0064 0065 %parser_bits_header "parserdebug.h" 0066 0067 ------------------------------------------------------------ 0068 -- Export macro to use the parser in a shared lib 0069 ------------------------------------------------------------ 0070 %export_macro "KDEVPHPPARSER_EXPORT" 0071 %export_macro_header "parserexport.h" 0072 0073 0074 ------------------------------------------------------------ 0075 -- Enumeration types for additional AST members, 0076 -- in the global "Php" namespace 0077 ------------------------------------------------------------ 0078 %namespace 0079 [: 0080 class Lexer; 0081 0082 enum ModifierFlags { 0083 ModifierPrivate = 1, 0084 ModifierPublic = 1 << 1, 0085 ModifierProtected = 1 << 2, 0086 ModifierStatic = 1 << 3, 0087 ModifierFinal = 1 << 4, 0088 ModifierAbstract = 1 << 5 0089 }; 0090 0091 enum ClassModifier { 0092 NormalClass, 0093 AbstractClass, 0094 FinalClass 0095 }; 0096 0097 enum ScalarTypes { 0098 ScalarTypeInt, 0099 ScalarTypeFloat, 0100 ScalarTypeString 0101 }; 0102 0103 enum CastType { 0104 CastInt, 0105 CastDouble, 0106 CastString, 0107 CastArray, 0108 CastObject, 0109 CastBool, 0110 CastUnset 0111 }; 0112 0113 enum OperationType { 0114 OperationPlus = 1, 0115 OperationMinus, 0116 OperationConcat, 0117 OperationMul, 0118 OperationDiv, 0119 OperationExp, 0120 OperationMod, 0121 OperationAnd, 0122 OperationOr, 0123 OperationXor, 0124 OperationSl, 0125 OperationSr, 0126 OperationSpaceship, 0127 }; 0128 0129 enum UseImportType { 0130 NamespaceOrClassImport, 0131 ConstantImport, 0132 FunctionImport 0133 }; 0134 0135 :] 0136 0137 ------------------------------------------------------------ 0138 -- Ast Node class members 0139 ------------------------------------------------------------ 0140 %ast_extra_members 0141 [: 0142 KDevelop::DUContext* ducontext; 0143 :] 0144 0145 ------------------------------------------------------------ 0146 -- Parser class members 0147 ------------------------------------------------------------ 0148 0149 %parserclass (public declaration) 0150 [: 0151 /** 0152 * Transform the raw input into tokens. 0153 * When this method returns, the parser's token stream has been filled 0154 * and any parse*() method can be called. 0155 */ 0156 void tokenize(const QString& contents, int initialState = Lexer::HtmlState); 0157 0158 enum ProblemType { 0159 Error, 0160 Warning, 0161 Info, 0162 Todo 0163 }; 0164 KDevelop::ProblemPointer reportProblem( Parser::ProblemType type, const QString& message, int tokenOffset = -1 ); 0165 QList<KDevelop::ProblemPointer> problems() { 0166 return m_problems; 0167 } 0168 QString tokenText(qint64 begin, qint64 end); 0169 void setDebug(bool debug); 0170 void setCurrentDocument(KDevelop::IndexedString url); 0171 void setTodoMarkers(const QStringList& markers); 0172 void extractTodosFromComment(const QString& comment, qint64 offset); 0173 0174 enum InitialLexerState { 0175 HtmlState = 0, 0176 DefaultState = 1 0177 }; 0178 0179 enum ParserUseImportType { 0180 NamespaceOrClassImport, 0181 ConstantImport, 0182 FunctionImport 0183 }; 0184 ParserUseImportType m_useImportType; 0185 ParserUseImportType m_useCompoundImportType; 0186 :] 0187 0188 %parserclass (private declaration) 0189 [: 0190 enum VarExpressionState { 0191 Normal, 0192 OnlyVariable, 0193 OnlyNewObject 0194 }; 0195 QString m_contents; 0196 bool m_debug; 0197 KDevelop::IndexedString m_currentDocument; 0198 QList<KDevelop::ProblemPointer> m_problems; 0199 0200 struct ParserState { 0201 VarExpressionState varExpressionState; 0202 bool varExpressionIsVariable; 0203 }; 0204 ParserState m_state; 0205 0206 QRegularExpression m_todoMarkers; 0207 :] 0208 0209 %parserclass (constructor) 0210 [: 0211 m_state.varExpressionState = Normal; 0212 m_state.varExpressionIsVariable = false; 0213 :] 0214 0215 0216 %token_stream TokenStream ;; 0217 0218 ----------------------------------------------------------- 0219 -- List of defined tokens 0220 ----------------------------------------------------------- 0221 0222 -- keywords: 0223 %token ABSTRACT ("abstract"), BREAK ("break"), CASE ("case"), CATCH ("catch"), 0224 CLASS ("class"), CONST ("const"), CONTINUE ("continue"), 0225 DEFAULT ("default"), DO ("do"), ELSE ("else"), EXTENDS ("extends"), 0226 FINAL ("final"), FOR ("for"), IF ("if"), 0227 IMPLEMENTS ("implements"), INSTANCEOF ("instanceof"), INTERFACE ("interface"), 0228 NEW ("new"), PRIVATE ("private"), PROTECTED ("protected"), PUBLIC ("public"), 0229 RETURN ("return"), STATIC ("static"), SWITCH ("switch"), THROW ("throw"), 0230 TRY ("try"), WHILE ("while"), ECHO ("echo"), PRINT ("print"), FINALLY ("finally"), 0231 CLONE ("clone"), EXIT ("exit"), ELSEIF ("elseif"), ENDIF ("endif"), 0232 ENDWHILE ("endwhile"), ENDFOR ("endfor"), FOREACH ("foreach"), ENDFOREACH ("endforeach"), 0233 DECLARE ("declare"), ENDDECLARE ("enddeclare"), AS ("as"), ENDSWITCH ("endswitch"), 0234 FUNCTION ("function"), USE ("use"), GLOBAL ("global"), VAR ("var "), UNSET ("unset"), 0235 ISSET ("isset"), EMPTY ("empty"), HALT_COMPILER ("halt compiler"), 0236 DOUBLE_ARROW ("=>"), LIST ("list"), ARRAY ("array"), CLASS_C ("__CLASS__"), 0237 METHOD_C ("__METHOD__"), FUNC_C ("__FUNCTION__"), LINE ("__LINE__"), 0238 FILE ("__FILE__"), COMMENT ("comment"), DOC_COMMENT ("doc comment"), PAAMAYIM_NEKUDOTAYIM ("::"), 0239 INCLUDE ("include"), INCLUDE_ONCE ("include_once"), EVAL ("eval"), REQUIRE ("require"), 0240 REQUIRE_ONCE ("require_once"), NAMESPACE ("namespace"), NAMESPACE_C("__NAMESPACE__"), USE("use"), 0241 GOTO ("goto"), TRAIT ("trait"), INSTEADOF ("insteadof"), CALLABLE ("callable"), 0242 VOID ("void"), DIR ("__DIR__"), TRAIT_C ("__TRAIT__"), YIELD ("yield"), YIELD_FROM("yield from") ;; 0243 0244 -- casts: 0245 %token INT_CAST ("int cast"), DOUBLE_CAST ("double cast"), STRING_CAST ("string cast"), 0246 ARRAY_CAST ("array cast"), OBJECT_CAST ("object cast"), BOOL_CAST ("bool cast"), 0247 UNSET_CAST ("unset cast") ;; 0248 0249 -- seperators: 0250 %token SEMICOLON (";"), DOUBLE_QUOTE ("\""), LBRACKET ("["), 0251 RBRACKET ("]"), 0252 LPAREN ("("), RPAREN (")"), LBRACE ("{"), RBRACE ("}"), 0253 COMMA (","), AT ("@"), 0254 CURLY_OPEN ("curly open"), -- { in "{$foo}"; not the same as LBRACE 0255 DOLLAR_OPEN_CURLY_BRACES ("${"), 0256 START_HEREDOC ("start heredoc"), END_HEREDOC ("end heredoc"), 0257 BACKTICK ("`"), BACKSLASH ("\\"), 0258 START_NOWDOC("start nowdoc"), END_NOWDOC("end nowdoc") ;; 0259 0260 -- operators: 0261 %token IS_EQUAL ("=="), IS_NOT_EQUAL ("!="), IS_IDENTICAL ("==="), 0262 IS_NOT_IDENTICAL ("!=="), IS_SMALLER ("<"), IS_GREATER (">"), 0263 IS_SMALLER_OR_EQUAL ("<="), IS_GREATER_OR_EQUAL (">="), 0264 BOOLEAN_OR ("||"), BOOLEAN_AND ("&&"), ASSIGN ("="), EXP_ASSIGN("**="), 0265 PLUS_ASSIGN ("+="), MINUS_ASSIGN ("-="), MUL_ASSIGN ("*="), DIV_ASSIGN ("/="), 0266 CONCAT_ASSIGN (".="), MOD_ASSIGN ("%="), AND_ASSIGN ("&="), OR_ASSIGN ("|="), 0267 XOR_ASSIGN ("^="), SL_ASSIGN ("<<="), SR_ASSIGN (">>="), OBJECT_OPERATOR ("->"), 0268 PLUS ("+"), MINUS("-"), CONCAT("."), 0269 INC ("++"), DEC ("--"), BANG ("!"), QUESTION ("?"), COLON (":"), 0270 BIT_AND ("&"), BIT_OR("|"), BIT_XOR ("^"), 0271 SL ("<<"), SR (">>"), MUL("*"), DIV("/"), MOD ("%"), 0272 TILDE ("~"), DOLLAR ("$"), EXP ("**"), ELLIPSIS ("..."), 0273 NULL_COALESCE ("??"), SPACESHIP ("<=>"), 0274 LOGICAL_OR ("logical or"), LOGICAL_AND ("logical and"), LOGICAL_XOR ("logical xor") ;; 0275 0276 -- literals and identifiers: 0277 %token INLINE_HTML ("inline html"), WHITESPACE ("whitespace"), 0278 CONSTANT_ENCAPSED_STRING ("constant encapsed string"), 0279 VARIABLE ("variable"), ENCAPSED_AND_WHITESPACE ("encapsed and whitespace"), 0280 DNUMBER ("double number"), LNUMBER ("long number"), 0281 NUM_STRING ("num string"), STRING ("string"), 0282 STRING_VARNAME ("string varname") ;; -- when in "${varname}" 0283 0284 -- open/close tags 0285 %token OPEN_TAG ("<?"), CLOSE_TAG ("?>"), OPEN_TAG_WITH_ECHO ("<?=");; 0286 0287 -- token that makes the parser fail in any case: 0288 %token INVALID ("invalid token") ;; 0289 0290 0291 0292 -- The actual grammar starts here. 0293 0294 #statements=outerTopStatement* 0295 -> start ;; 0296 0297 namespaceDeclaration=namespaceDeclarationStatement 0298 | statement=topStatement 0299 -> outerTopStatement ;; 0300 0301 -- first/first conflict for FUNCTION 0302 (?[: (LA(1).kind == Token_FUNCTION && ((LA(2).kind == Token_BIT_AND && LA(3).kind == Token_LPAREN) 0303 || LA(2).kind == Token_LPAREN)) 0304 || LA(1).kind != Token_FUNCTION :] 0305 statement=statement ) 0306 | functionDeclaration=functionDeclarationStatement 0307 | classDeclaration=classDeclarationStatement 0308 | traitDeclaration=traitDeclarationStatement 0309 | interfaceDeclaration=interfaceDeclarationStatement 0310 | HALT_COMPILER LPAREN RPAREN SEMICOLON -- Lexer stops allready 0311 -> topStatement ;; 0312 0313 [: bool reported = false; while ( true ) { :] 0314 try/recover(#statements=topStatement)* 0315 [: if (yytoken != Token_RBRACE && yytoken != Token_EOF && yytoken != Token_CLOSE_TAG 0316 && yytoken != Token_ELSEIF && yytoken != Token_ELSE 0317 && yytoken != Token_ENDIF && yytoken != Token_ENDFOREACH && yytoken != Token_ENDFOR 0318 && yytoken != Token_ENDWHILE && yytoken != Token_ENDSWITCH && yytoken != Token_ENDDECLARE 0319 && yytoken != Token_CASE && yytoken != Token_DEFAULT) { 0320 if (!reported) { 0321 qint64 index = tokenStream->index() - 1; 0322 Token &token = tokenStream->at(index); 0323 QString tokenValue = token.kind != 0 ? tokenText(token.begin, token.end) : QStringLiteral("EOF"); 0324 reportProblem(Error, QStringLiteral("Unexpected token \"%1\".").arg(tokenValue)); 0325 reported = true; 0326 } 0327 yylex(); 0328 } else { 0329 break; 0330 } 0331 } :] 0332 -> innerStatementList ;; 0333 0334 --Operator Precedence, from PHP Manual 0335 --left or 0336 --left xor 0337 --left and 0338 --right print 0339 --right = += -= *= /= .= %= &= |= ^= <<= >>= assignment 0340 --left ? : ternary 0341 --right ?? comparison 0342 --left || logical 0343 --left && logical 0344 --left | bitwise 0345 --left ^ bitwise 0346 --left & bitwise and references 0347 --non-associative == != === !== <=> comparison 0348 --non-associative < <= > >= comparison 0349 --left << >> bitwise 0350 --left + - . arithmetic and string 0351 --left * / % arithmetic 0352 --non-associative ! ~ - (int) (float) (string) (array) (object) @ types 0353 --non-associative ++ -- increment/decrement 0354 --left [ array() 0355 --non-associative new new 0356 0357 expression=logicalOrExpression 0358 -> expr ;; 0359 0360 #expression=logicalXorExpression @ LOGICAL_OR 0361 -> logicalOrExpression ;; 0362 0363 #expression=logicalAndExpression @ LOGICAL_XOR 0364 -> logicalXorExpression ;; 0365 0366 #expression=printExpression @ LOGICAL_AND 0367 -> logicalAndExpression ;; 0368 0369 (print=PRINT | 0) expression=assignmentExpression 0370 -> printExpression ;; 0371 0372 -- leftside must me a variable, we check afterwards if it was a variable and 0373 -- if not we report an error 0374 0 --needed for line below 0375 [: m_state.varExpressionIsVariable = false; :] --reset flag 0376 expression=conditionalExpression 0377 ( 0378 assignmentExpressionEqual=assignmentExpressionEqual | ( 0379 ( 0380 PLUS_ASSIGN [: (*yynode)->operation = OperationPlus; :] 0381 | MINUS_ASSIGN [: (*yynode)->operation = OperationMinus; :] 0382 | MUL_ASSIGN [: (*yynode)->operation = OperationMul; :] 0383 | EXP_ASSIGN [: (*yynode)->operation = OperationExp; :] 0384 | DIV_ASSIGN [: (*yynode)->operation = OperationDiv; :] 0385 | CONCAT_ASSIGN [: (*yynode)->operation = OperationConcat; :] 0386 | MOD_ASSIGN [: (*yynode)->operation = OperationMod; :] 0387 | AND_ASSIGN [: (*yynode)->operation = OperationAnd; :] 0388 | OR_ASSIGN [: (*yynode)->operation = OperationOr; :] 0389 | XOR_ASSIGN [: (*yynode)->operation = OperationXor; :] 0390 | SL_ASSIGN [: (*yynode)->operation = OperationSl; :] 0391 | SR_ASSIGN [: (*yynode)->operation = OperationSr; :] 0392 ) 0393 assignmentExpressionCheckIfVariable 0394 assignmentExpression=assignmentExpression) 0395 | 0) 0396 -> assignmentExpression [ 0397 member variable operation: OperationType; 0398 ];; 0399 0400 --=& is special: 0401 -- $foo =& $var; is allowed but not $foo =& 'static'; 0402 -- $foo =& new bar(); is allowed too but deprecated and reports a warning 0403 --we set a flag (varExpressionState) with that var_expression accepts only valid parts 0404 --this is done in such a strage way because we need the full expression to allow 0405 --things like $foo =& $bar || e(); 0406 ASSIGN 0407 assignmentExpressionCheckIfVariable --as in assignmentExpression 0408 (BIT_AND [: if (yytoken == Token_NEW) { 0409 reportProblem(Warning, QStringLiteral("=& new foo() is deprecated"), -2); 0410 m_state.varExpressionState = OnlyNewObject; 0411 } else { 0412 m_state.varExpressionState = OnlyVariable; 0413 }:] 0414 | 0) assignmentExpression=assignmentExpression [: m_state.varExpressionState = Normal; :] 0415 -> assignmentExpressionEqual ;; 0416 0417 0418 -- check if var_expression was a variable, if not report an error 0419 -- varExpressionIsVariable is set in var_expression 0420 0 --to allow cpp-code 0421 [: 0422 if (!m_state.varExpressionIsVariable) { 0423 reportProblem(Error, QStringLiteral("Left side is not a variable")); 0424 return false; 0425 } 0426 :] 0427 -> assignmentExpressionCheckIfVariable ;; 0428 0429 expression=nullCoalesceExpression 0430 ( QUESTION (ifExpression=expr|0) 0431 COLON elseExpression=conditionalExpression 0432 | 0 0433 ) 0434 -> conditionalExpression ;; 0435 0436 #expression=booleanOrExpression @ NULL_COALESCE 0437 -> nullCoalesceExpression ;; 0438 0439 #expression=booleanAndExpression @ BOOLEAN_OR 0440 -> booleanOrExpression ;; 0441 0442 #expression=bitOrExpression @ BOOLEAN_AND 0443 -> booleanAndExpression ;; 0444 0445 #expression=bitXorExpression @ BIT_OR 0446 -> bitOrExpression ;; 0447 0448 #expression=bitAndExpression @ BIT_XOR 0449 -> bitXorExpression ;; 0450 0451 #expression=equalityExpression @ BIT_AND 0452 -> bitAndExpression ;; 0453 0454 expression=relationalExpression 0455 (additionalExpression=equalityExpressionRest | 0) 0456 -> equalityExpression ;; 0457 0458 ( IS_EQUAL | IS_NOT_EQUAL | IS_IDENTICAL | IS_NOT_IDENTICAL | SPACESHIP [: (*yynode)->operation = OperationSpaceship; :] ) 0459 expression=relationalExpression 0460 -> equalityExpressionRest [ 0461 member variable operation: OperationType; 0462 ];; 0463 0464 0465 expression=shiftExpression 0466 ( additionalExpression=relationalExpressionRest 0467 --instanceof as in java.g (correct??) 0468 | INSTANCEOF instanceofType=classNameReference 0469 | 0 0470 ) 0471 -> relationalExpression ;; 0472 0473 ( IS_SMALLER | IS_GREATER | IS_SMALLER_OR_EQUAL | IS_GREATER_OR_EQUAL ) 0474 expression=shiftExpression 0475 -> relationalExpressionRest ;; 0476 0477 0478 expression=additiveExpression 0479 (#additionalExpression=shiftExpressionRest)* 0480 -> shiftExpression ;; 0481 0482 ( SL | SR ) 0483 expression=additiveExpression 0484 -> shiftExpressionRest ;; 0485 0486 0487 expression=multiplicativeExpression 0488 (#additionalExpression=additiveExpressionRest)* 0489 -> additiveExpression ;; 0490 0491 ( 0492 PLUS [: (*yynode)->operation = OperationPlus; :] 0493 | MINUS [: (*yynode)->operation = OperationMinus; :] 0494 | CONCAT [: (*yynode)->operation = OperationConcat; :] 0495 ) 0496 expression=multiplicativeExpression 0497 -> additiveExpressionRest [ 0498 member variable operation: OperationType; 0499 ];; 0500 0501 0502 expression=unaryExpression 0503 (#additionalExpression=multiplicativeExpressionRest)* 0504 -> multiplicativeExpression ;; 0505 0506 ( 0507 MUL [: (*yynode)->operation = OperationMul; :] 0508 | DIV [: (*yynode)->operation = OperationDiv; :] 0509 | EXP [: (*yynode)->operation = OperationExp; :] 0510 | MOD [: (*yynode)->operation = OperationMod; :] 0511 ) 0512 expression=unaryExpression 0513 -> multiplicativeExpressionRest [ 0514 member variable operation: OperationType; 0515 ];; 0516 0517 ( 0518 MINUS unaryExpression=unaryExpression 0519 | PLUS unaryExpression=unaryExpression 0520 | BANG unaryExpression=unaryExpression 0521 | TILDE unaryExpression=unaryExpression 0522 | INT_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastInt; :] 0523 | DOUBLE_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastDouble; :] 0524 | STRING_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastString; :] 0525 | ARRAY_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastArray; :] 0526 | OBJECT_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastObject; :] 0527 | BOOL_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastBool; :] 0528 | UNSET_CAST unaryExpression=unaryExpression [: (*yynode)->castType = CastUnset; :] 0529 | AT unaryExpression=unaryExpression 0530 | LIST LPAREN assignmentList=assignmentList RPAREN ASSIGN unaryExpression=unaryExpression 0531 | EXIT (LPAREN (expression=expr | 0) RPAREN | 0) 0532 | EVAL LPAREN expression=expr RPAREN 0533 | INCLUDE includeExpression=unaryExpression 0534 | INCLUDE_ONCE includeExpression=unaryExpression 0535 | REQUIRE includeExpression=unaryExpression 0536 | REQUIRE_ONCE includeExpression=unaryExpression 0537 0538 | unaryExpressionNotPlusminus=unaryExpressionNotPlusminus 0539 ) 0540 -> unaryExpression [ 0541 member variable castType: CastType; 0542 ];; 0543 0544 (#prefixOperator=postprefixOperator)* 0545 varExpression=varExpression 0546 (#postfixOperator=postprefixOperator)* 0547 -> unaryExpressionNotPlusminus ;; 0548 0549 op=INC | op=DEC 0550 -> postprefixOperator ;; 0551 0552 -- 10 first follow conflicts because we go back up the chain (affects both print and yield) 0553 (print=PRINT+) printExpression=assignmentExpression 0554 | isGenerator=YIELD (generatorExpression=printExpression ( DOUBLE_ARROW generatorValueExpr=printExpression | 0 ) | 0) 0555 | isGenerator=YIELD_FROM generatorExpression=printExpression 0556 --first/first conflict - no problem because of ifs 0557 | ?[: m_state.varExpressionState == OnlyVariable :] 0 [: m_state.varExpressionState = Normal; :] variable=variable 0558 | ?[: m_state.varExpressionState == OnlyNewObject :] 0 [: m_state.varExpressionState = Normal; :] newObject=varExpressionNewObject 0559 | varExpressionNormal=varExpressionNormal 0560 | varExpressionArray=varExpressionArray arrayIndex=arrayIndexSpecifier* 0561 -> varExpression ;; 0562 0563 (?[: LA(1).kind == Token_LPAREN && LA(2).kind == Token_FUNCTION && LA(3).kind == Token_LPAREN :] iife=iifeSyntax ) 0564 | LPAREN try/rollback (newObject=varExpressionNewObject RPAREN (#variableProperties=instantiationAccess*)) 0565 catch (expression=expr RPAREN) 0566 | BACKTICK encapsList=encapsList BACKTICK 0567 --try/rollback resolves conflict scalar vs. staticMember (foo::bar vs. foo::$bar) 0568 --varExpressionIsVariable flag is needed for assignmentExpression 0569 | try/rollback (variable=variable [: m_state.varExpressionIsVariable = true; :]) 0570 catch (scalar=scalar) 0571 | ISSET LPAREN (#issetVariable=variable @ COMMA) RPAREN 0572 | EMPTY LPAREN emptyExpression=expr RPAREN 0573 | newObject=varExpressionNewObject 0574 | CLONE cloneCar=varExpressionNormal 0575 | closure=closure 0576 -> varExpressionNormal ;; 0577 0578 ARRAY LPAREN 0579 (#arrayValues=arrayPairValue 0580 -- break because array(1,) is allowed (solves FIRST/FOLLOW conflict) 0581 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0) 0582 RPAREN 0583 | LBRACKET 0584 (#arrayValues=arrayPairValue 0585 -- break because [1,] is allowed (solves FIRST/FOLLOW conflict) 0586 @ (COMMA [: if (yytoken == Token_RBRACKET) { break; } :] ) | 0) 0587 RBRACKET 0588 -> varExpressionArray ;; 0589 0590 -- https://wiki.php.net/rfc/closures 0591 FUNCTION (isRef=BIT_AND|0) LPAREN parameters=parameterList RPAREN 0592 ( USE LPAREN lexicalVars=lexicalVarList RPAREN | 0) 0593 ( COLON returnType=returnType | 0) 0594 LBRACE try/recover(functionBody=innerStatementList) RBRACE 0595 -> closure ;; 0596 0597 LPAREN try/rollback (closure=closure RPAREN LPAREN parameterList=functionCallParameterList RPAREN) 0598 catch (expression=expr RPAREN) 0599 -> iifeSyntax ;; 0600 0601 (#lexicalVars=lexicalVar 0602 -- break because (1,) is allowed 0603 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0 [: reportProblem(Error, QStringLiteral("Use list of closure must not be empty.")); :]) 0604 -> lexicalVarList ;; 0605 0606 (isRef=BIT_AND | 0) variable=variableIdentifier 0607 -> lexicalVar ;; 0608 0609 NEW classNameReference=classNameReference ctor=ctorArguments 0610 -> varExpressionNewObject ;; 0611 0612 LPAREN parameterList=functionCallParameterList RPAREN 0613 | 0 0614 -> ctorArguments ;; 0615 0616 (#parameters=functionCallParameterListElement 0617 -- break because (1,) is allowed 0618 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0) 0619 -> functionCallParameterList ;; 0620 0621 (BIT_AND variable=variable) | (isVariadic=ELLIPSIS | 0) expr=expr 0622 -> functionCallParameterListElement ;; 0623 0624 #element=assignmentListElement @COMMA 0625 -> assignmentList ;; 0626 0627 variable=variable 0628 | LIST LPAREN assignmentList=assignmentList RPAREN 0629 | 0 0630 -> assignmentListElement ;; 0631 0632 expr=expr (DOUBLE_ARROW (exprValue=expr | BIT_AND varValue=variable) | 0) 0633 | BIT_AND variable=variable 0634 -> arrayPairValue ;; 0635 0636 var=baseVariableWithFunctionCalls (#variableProperties=variableObjectProperty*) 0637 -> variable ;; 0638 0639 OBJECT_OPERATOR 0640 | PAAMAYIM_NEKUDOTAYIM 0641 -> objectOperator ;; 0642 0643 ( ?[: LA(1).kind == Token_DOLLAR:] LBRACE variable=variable RBRACE | objectProperty=objectProperty ) 0644 (isFunctionCall=LPAREN parameterList=functionCallParameterList RPAREN arrayIndex=arrayIndexSpecifier* | 0) 0645 -> variableProperty ;; 0646 0647 objectOperator variableProperty=variableProperty 0648 -> variableObjectProperty ;; 0649 0650 OBJECT_OPERATOR variableProperty=variableProperty 0651 -> instantiationAccess ;; 0652 0653 --Conflict 0654 -- foo::$bar[0] (=baseVariable-staticMember) 0655 --vs.foo::$bar[0](); (=static function call) 0656 try/rollback (functionCall=functionCall arrayIndex=arrayIndexSpecifier*) 0657 catch (baseVariable=baseVariable) 0658 -> baseVariableWithFunctionCalls ;; 0659 0660 LBRACKET (expr=expr | 0) RBRACKET 0661 -> arrayIndexSpecifier ;; 0662 0663 LBRACKET (expr=expr) RBRACKET 0664 -> stringIndexSpecifier ;; 0665 0666 stringFunctionNameOrClass=namespacedIdentifier ( 0667 LPAREN stringParameterList=functionCallParameterList RPAREN 0668 | PAAMAYIM_NEKUDOTAYIM 0669 ( 0670 stringFunctionName=semiReservedIdentifier LPAREN stringParameterList=functionCallParameterList RPAREN 0671 | varFunctionName=variableWithoutObjects LPAREN stringParameterList=functionCallParameterList RPAREN 0672 | LBRACE (expr=expr) RBRACE LPAREN stringParameterList=functionCallParameterList RPAREN 0673 ) 0674 ) 0675 | varFunctionName=variableWithoutObjects LPAREN varParameterList=functionCallParameterList RPAREN 0676 -> functionCall ;; 0677 0678 var=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem* 0679 | staticMember=staticMember 0680 -> baseVariable ;; 0681 0682 variable=variableIdentifier 0683 | DOLLAR LBRACE expr=expr RBRACE 0684 -> compoundVariable ;; 0685 0686 ( DOLLAR ( DOLLAR+ | 0 ) ( indirectVariable=variableIdentifier | LBRACE expr=expr RBRACE ) | variable=variableIdentifier ) 0687 -> compoundVariableWithSimpleIndirectReference ;; 0688 0689 className=namespacedIdentifier staticProperty=staticProperty 0690 -> staticMember ;; 0691 0692 LBRACE try/recover(statements=innerStatementList) RBRACE 0693 | IF LPAREN ifExpr=expr RPAREN 0694 ( COLON statements=innerStatementList newElseifList newElseSingle ENDIF semicolonOrCloseTag 0695 | ifStatement=statement elseifList=elseifList elseSingle=elseSingle 0696 ) 0697 | WHILE LPAREN whileExpr=expr RPAREN whileStatement=whileStatement 0698 | FOR LPAREN forExpr1=forExpr SEMICOLON forExpr2=forExpr 0699 SEMICOLON forExpr3=forExpr RPAREN forStatement=forStatement 0700 | SWITCH LPAREN swtichExpr=expr RPAREN switchCaseList=switchCaseList 0701 0702 | FOREACH LPAREN ( 0703 -- allow $var as &$i and not expr() as &$i 0704 try/rollback(foreachVar=variable AS foreachVarAsVar=foreachVariable) 0705 catch(foreachExpr=expr AS foreachExprAsVar=variable)) 0706 (DOUBLE_ARROW foreachVariable=foreachVariable | 0) RPAREN 0707 foreachStatement=foreachStatement 0708 | DECLARE LPAREN declareItem=declareItem @ COMMA RPAREN declareStatement 0709 | SEMICOLON -- empty statement 0710 | TRY LBRACE try/recover(statements=innerStatementList) RBRACE 0711 #catches=catchItem* 0712 (FINALLY LBRACE finallyBody=innerStatementList RBRACE | 0) 0713 | UNSET LPAREN #unsetVariables=variable @ COMMA RPAREN semicolonOrCloseTag 0714 -- fix first/follow with goto target 0715 | ( ?[: LA(1).kind != Token_STRING || LA(2).kind != Token_COLON :] expr=expr semicolonOrCloseTag ) 0716 | DO doStatement=statement WHILE LPAREN whileExpr=expr RPAREN semicolonOrCloseTag 0717 | BREAK (breakExpr=expr | 0) semicolonOrCloseTag 0718 | CONTINUE (continueExpr=expr | 0) semicolonOrCloseTag 0719 | RETURN (returnExpr=expr | 0) semicolonOrCloseTag 0720 | GLOBAL #globalVars=globalVar @ COMMA semicolonOrCloseTag 0721 | STATIC #staticVars=staticVar @ COMMA semicolonOrCloseTag 0722 | ECHO #echoExprs=expr @ COMMA semicolonOrCloseTag 0723 | THROW throwExpr=expr semicolonOrCloseTag 0724 -- throws error in zend parser, so ignored | USE use_filename semicolonOrCloseTag 0725 0726 | CLOSE_TAG 0727 | OPEN_TAG 0728 | OPEN_TAG_WITH_ECHO expr=expr semicolonOrCloseTag 0729 | INLINE_HTML 0730 | CONST #consts=constantDeclaration @ COMMA SEMICOLON 0731 | USE useStatement=useStatement 0732 | GOTO gotoLabel=STRING SEMICOLON 0733 | gotoTarget=STRING COLON 0734 -> statement ;; 0735 0736 ( useFunction=FUNCTION [: m_useImportType = FunctionImport; :] 0737 | useConst=CONST [: m_useImportType = ConstantImport; :] 0738 | 0 [: m_useImportType = NamespaceOrClassImport; :] 0739 ) #useNamespace=useNamespaceOrUseGroupedNamespace @ COMMA SEMICOLON 0740 -> useStatement ;; 0741 0742 [: (*yynode)->useImportType = (UseImportType)(int)m_useImportType; :] 0743 identifier=namespacedIdentifierBeforeGroupedNamespace 0744 (AS aliasIdentifier=identifier | compoundNamespace=compoundNamespace | 0) 0745 -> useNamespaceOrUseGroupedNamespace [ 0746 member variable useImportType: UseImportType; 0747 ] ;; 0748 0749 LBRACE 0750 #compoundNamespaceStatement=compoundNamespaceStatement 0751 -- break because "use Foo\{bar1,}" is allowed (solves FIRST/FOLLOW conflict) 0752 @ (COMMA [: if (yytoken == Token_RBRACE) { break; } :] ) 0753 RBRACE 0754 -> compoundNamespace ;; 0755 0756 ( useFunction=FUNCTION [: m_useCompoundImportType = FunctionImport; :] 0757 | useConst=CONST [: m_useCompoundImportType = ConstantImport; :] 0758 | 0 [: m_useCompoundImportType = NamespaceOrClassImport; :] 0759 ) 0760 [: 0761 if (m_useImportType != NamespaceOrClassImport && m_useCompoundImportType != NamespaceOrClassImport) 0762 { 0763 reportProblem(Error, QStringLiteral("Can't use mixed import."), -2); 0764 } 0765 :] 0766 #useNamespace=innerUseNamespace 0767 -> compoundNamespaceStatement ;; 0768 0769 [: 0770 if (m_useCompoundImportType != NamespaceOrClassImport) { 0771 (*yynode)->useImportType = (UseImportType)(int)m_useCompoundImportType; 0772 } else { 0773 (*yynode)->useImportType = (UseImportType)(int)m_useImportType; 0774 } 0775 :] 0776 #namespaceName=identifier+ @ BACKSLASH 0777 (AS aliasIdentifier=identifier | 0) 0778 -> innerUseNamespace [ 0779 member variable useImportType: UseImportType; 0780 ] ;; 0781 0782 identifier=identifier ASSIGN scalar=expr 0783 -> constantDeclaration ;; 0784 0785 identifier=semiReservedIdentifier ASSIGN scalar=expr 0786 -> classConstantDeclaration ;; 0787 0788 SEMICOLON | CLOSE_TAG 0789 -> semicolonOrCloseTag ;; 0790 0791 LBRACE (SEMICOLON | 0) try/recover(caseList=caseList) RBRACE 0792 | COLON (SEMICOLON | 0) caseList=caseList ENDSWITCH semicolonOrCloseTag 0793 -> switchCaseList ;; 0794 0795 #caseItems=case_item* 0796 -> caseList ;; 0797 0798 CASE expr=expr (COLON | SEMICOLON) statements=innerStatementList 0799 | def=DEFAULT (COLON | SEMICOLON) statements=innerStatementList 0800 -> case_item ;; 0801 0802 CATCH LPAREN #catchClass=namespacedIdentifier @ BIT_OR var=variableIdentifier RPAREN 0803 LBRACE try/recover(statements=innerStatementList) RBRACE 0804 -> catchItem ;; 0805 0806 statement=statement 0807 | COLON statements=innerStatementList ENDDECLARE semicolonOrCloseTag 0808 -> declareStatement ;; 0809 0810 STRING ASSIGN scalar=staticScalar 0811 -> declareItem ;; 0812 0813 (BIT_AND | 0) variable=variable 0814 -> foreachVariable ;; 0815 0816 statement=statement 0817 | COLON statements=innerStatementList ENDFOREACH semicolonOrCloseTag 0818 -> foreachStatement ;; 0819 0820 var=variableIdentifier (ASSIGN value=staticScalar | 0) 0821 -> staticVar ;; 0822 0823 var=variableIdentifier 0824 | DOLLAR (dollarVar=variable | LBRACE expr=expr RBRACE) 0825 -> globalVar ;; 0826 0827 #exprs=expr @ COMMA | 0 0828 -> forExpr ;; 0829 0830 statement=statement 0831 | COLON statements=innerStatementList ENDFOR semicolonOrCloseTag 0832 -> forStatement ;; 0833 0834 statement=statement 0835 | COLON statements=innerStatementList ENDWHILE semicolonOrCloseTag 0836 -> whileStatement ;; 0837 0838 --first/follow conflict; todo check if this is a problem 0839 #elseifListItem=elseifListItem* 0840 -> elseifList ;; 0841 0842 ELSEIF LPAREN expr=expr RPAREN statement=statement 0843 -> elseifListItem ;; 0844 0845 ELSE statement=statement | 0 0846 -> elseSingle ;; 0847 0848 #newElseifListItem=newelseifListItem* 0849 -> newElseifList ;; 0850 0851 ELSEIF LPAREN expr=expr RPAREN COLON statements=innerStatementList 0852 -> newelseifListItem ;; 0853 0854 ELSE COLON statements=innerStatementList | 0 0855 -> newElseSingle ;; 0856 0857 className=className (staticProperty=staticProperty #properties=classProperty* | 0) 0858 | baseVariable=variableWithoutObjects #properties=classProperty* 0859 -> classNameReference ;; 0860 0861 identifier=namespacedIdentifier 0862 | staticIdentifier = STATIC 0863 -> className ;; 0864 0865 PAAMAYIM_NEKUDOTAYIM staticProperty=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem* 0866 -> staticProperty ;; 0867 0868 (staticProperty=staticProperty | OBJECT_OPERATOR property=objectProperty) 0869 -> classProperty ;; 0870 0871 objectDimList=objectDimList 0872 | variableWithoutObjects=variableWithoutObjects 0873 -> objectProperty ;; 0874 0875 variableName=variableName #offsetItems=dimListItem* 0876 -> objectDimList ;; 0877 0878 variable=compoundVariableWithSimpleIndirectReference #offsetItems=dimListItem* 0879 -> variableWithoutObjects ;; 0880 0881 arrayIndex=arrayIndexSpecifier | LBRACE expr=expr RBRACE 0882 -> dimListItem ;; 0883 0884 name=identifier 0885 | LBRACE expr=expr RBRACE 0886 -> variableName ;; 0887 0888 commonScalar=commonScalar 0889 | constantOrClassConst=constantOrClassConst #offsetItem=dimListItem* 0890 | varname=STRING_VARNAME 0891 | DOUBLE_QUOTE encapsList=encapsList DOUBLE_QUOTE stringIndex=stringIndexSpecifier* 0892 | START_HEREDOC encapsList=encapsList END_HEREDOC 0893 -> scalar ;; 0894 0895 constant=namespacedIdentifier 0896 ( PAAMAYIM_NEKUDOTAYIM classConstant=classConstant | 0 ) 0897 -> constantOrClassConst ;; 0898 0899 semiReservedIdentifier 0900 -> classConstant ;; 0901 0902 #encaps=encaps* 0903 -> encapsList ;; 0904 0905 var=encapsVar | value=ENCAPSED_AND_WHITESPACE 0906 -> encaps ;; 0907 0908 -- first/first conflict resolved by LA(2) 0909 --(expr allows STRING_VARNAME too - but without [expr]) 0910 DOLLAR_OPEN_CURLY_BRACES ( ?[: LA(2).kind == Token_LBRACKET:] STRING_VARNAME arrayIndex=arrayIndexSpecifier RBRACE 0911 | expr=expr RBRACE ) 0912 | variable=variableIdentifier (OBJECT_OPERATOR propertyIdentifier=identifier | LBRACKET offset=encapsVarOffset RBRACKET | 0) 0913 | CURLY_OPEN expr=expr RBRACE 0914 -> encapsVar ;; 0915 0916 STRING 0917 | NUM_STRING 0918 | variableIdentifier 0919 -> encapsVarOffset ;; 0920 0921 0922 LNUMBER [: (*yynode)->scalarType = ScalarTypeInt; :] 0923 | DNUMBER [: (*yynode)->scalarType = ScalarTypeFloat; :] 0924 | string=CONSTANT_ENCAPSED_STRING [: (*yynode)->scalarType = ScalarTypeString; :] stringIndex=stringIndexSpecifier* 0925 | LINE [: (*yynode)->scalarType = ScalarTypeInt; :] 0926 | DIR [: (*yynode)->scalarType = ScalarTypeString; :] 0927 | FILE [: (*yynode)->scalarType = ScalarTypeString; :] 0928 | CLASS_C [: (*yynode)->scalarType = ScalarTypeString; :] 0929 | TRAIT_C [: (*yynode)->scalarType = ScalarTypeString; :] 0930 | METHOD_C [: (*yynode)->scalarType = ScalarTypeString; :] 0931 | FUNC_C [: (*yynode)->scalarType = ScalarTypeString; :] 0932 | NAMESPACE_C [: (*yynode)->scalarType = ScalarTypeString; :] 0933 | START_NOWDOC STRING END_NOWDOC [: (*yynode)->scalarType = ScalarTypeString; :] 0934 -> commonScalar [ 0935 member variable scalarType: ScalarTypes; 0936 ] ;; 0937 0938 FUNCTION (BIT_AND | 0) functionName=identifier 0939 LPAREN parameters=parameterList RPAREN (COLON returnType=returnType | 0) 0940 LBRACE try/recover(functionBody=innerStatementList) RBRACE 0941 -> functionDeclarationStatement ;; 0942 0943 (#parameters=parameter 0944 -- break because (1,) is allowed 0945 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0) 0946 -> parameterList ;; 0947 0948 (parameterType=parameterType | 0) (isRef=BIT_AND | 0) 0949 (isVariadic=ELLIPSIS | 0) variable=variableIdentifier (ASSIGN defaultValue=expr | 0) 0950 -> parameter ;; 0951 0952 genericType=namespacedIdentifier 0953 | arrayType=ARRAY 0954 -> genericTypeHint ;; 0955 0956 (isNullable=QUESTION | 0) ( 0957 genericType=genericTypeHint 0958 | callableType=CALLABLE 0959 ) 0960 [: (*yynode)->voidType = -1; :] 0961 -> parameterTypeHint[ 0962 member variable voidType: int; 0963 ] ;; 0964 0965 (isNullable=QUESTION | 0) ( 0966 genericType=genericTypeHint 0967 | callableType=CALLABLE 0968 | voidType=VOID 0969 ) 0970 -> returnTypeHint ;; 0971 0972 (isNullable=QUESTION | 0) 0973 genericType=genericTypeHint 0974 [: (*yynode)->callableType = -1; :] 0975 [: (*yynode)->voidType = -1; :] 0976 -> propertyTypeHint[ 0977 member variable callableType: int; 0978 member variable voidType: int; 0979 ] ;; 0980 0981 #unionType=parameterTypeHint @ BIT_OR 0982 -> unionParameterType ;; 0983 0984 typehint=unionParameterType 0985 -> parameterType ;; 0986 0987 #unionType=returnTypeHint @ BIT_OR 0988 -> unionReturnType ;; 0989 0990 typehint=unionReturnType 0991 -> returnType ;; 0992 0993 #unionType=propertyTypeHint @ BIT_OR 0994 -> unionPropertyType ;; 0995 0996 typehint=unionPropertyType 0997 -> propertyType ;; 0998 0999 value=commonScalar 1000 | constantOrClassConst=constantOrClassConst 1001 | PLUS plusValue=staticScalar 1002 | MINUS minusValue=staticScalar 1003 | array=ARRAY LPAREN 1004 (#arrayValues=staticArrayPairValue 1005 -- break because array(1,) is allowed 1006 @ (COMMA [: if (yytoken == Token_RPAREN) { break; } :] ) | 0) 1007 RPAREN 1008 | array=LBRACKET 1009 (#arrayValues=staticArrayPairValue 1010 -- break because [1,] is allowed 1011 @ (COMMA [: if (yytoken == Token_RBRACKET) { break; } :] ) | 0) 1012 RBRACKET 1013 -> staticScalar ;; 1014 1015 #val1=staticScalar (DOUBLE_ARROW #val2=staticScalar | 0) 1016 -> staticArrayPairValue ;; 1017 1018 (isGlobal=BACKSLASH | 0) 1019 #namespaceName=identifier+ @ BACKSLASH 1020 -> namespacedIdentifier ;; 1021 1022 (isGlobal=BACKSLASH | 0) 1023 #namespaceName=identifier+ @ ( BACKSLASH [: if (yytoken == Token_LBRACE) { break; } :] ) 1024 -> namespacedIdentifierBeforeGroupedNamespace ;; 1025 1026 string=STRING 1027 -> identifier ;; 1028 1029 INCLUDE | INCLUDE_ONCE | EVAL | REQUIRE | REQUIRE_ONCE | LOGICAL_OR | LOGICAL_XOR | LOGICAL_AND 1030 | INSTANCEOF | NEW | CLONE | EXIT | IF | ELSEIF | ELSE | ENDIF | ECHO | DO | WHILE | ENDWHILE 1031 | FOR | ENDFOR | FOREACH | ENDFOREACH | DECLARE | ENDDECLARE | AS | TRY | CATCH | FINALLY 1032 | THROW | USE | INSTEADOF | GLOBAL | VAR | UNSET | ISSET | EMPTY | CONTINUE | GOTO 1033 | FUNCTION | CONST | RETURN | PRINT | YIELD | LIST | SWITCH | ENDSWITCH | CASE | DEFAULT | BREAK 1034 | ARRAY | CALLABLE | EXTENDS | IMPLEMENTS | NAMESPACE | TRAIT | INTERFACE | CLASS 1035 | CLASS_C | TRAIT_C | FUNC_C | METHOD_C | LINE | FILE | DIR | NAMESPACE_C 1036 -> reservedNonModifiers ;; 1037 1038 reservedNonModifiers 1039 | STATIC | ABSTRACT | FINAL | PRIVATE | PROTECTED | PUBLIC 1040 -> semiReserved ;; 1041 1042 identifier 1043 [: 1044 qint64 index = tokenStream->index() - 2; 1045 (*yynode)->string = index; 1046 :] 1047 | semiReserved 1048 [: 1049 qint64 index = tokenStream->index() - 2; 1050 (*yynode)->string = index; 1051 :] 1052 -> semiReservedIdentifier [ 1053 member variable string: qint64; 1054 ] ;; 1055 1056 identifier 1057 [: 1058 qint64 index = tokenStream->index() - 2; 1059 (*yynode)->string = index; 1060 :] 1061 | reservedNonModifiers 1062 [: 1063 qint64 index = tokenStream->index() - 2; 1064 (*yynode)->string = index; 1065 :] 1066 -> reservedNonModifierIdentifier [ 1067 member variable string: qint64; 1068 ] ;; 1069 1070 variable=VARIABLE 1071 -> variableIdentifier ;; 1072 1073 NAMESPACE #namespaceName=identifier* @ BACKSLASH 1074 ( 1075 -- the semicolon case needs at least one namespace identifier, the {...} case not... 1076 SEMICOLON [: if (!(*yynode)->namespaceNameSequence) { reportProblem(Error, QStringLiteral("Missing namespace identifier."), -2); } :] 1077 | LBRACE try/recover(body=innerStatementList) RBRACE ) 1078 -> namespaceDeclarationStatement ;; 1079 1080 INTERFACE interfaceName=identifier (EXTENDS extends=classImplements | 0) 1081 LBRACE try/recover(body=classBody) RBRACE 1082 -> interfaceDeclarationStatement ;; 1083 1084 TRAIT traitName=identifier 1085 LBRACE body=classBody RBRACE 1086 -> traitDeclarationStatement ;; 1087 1088 modifier=optionalClassModifier CLASS className=identifier 1089 (EXTENDS extends=classExtends | 0) 1090 (IMPLEMENTS implements=classImplements | 0) 1091 LBRACE body=classBody RBRACE 1092 -> classDeclarationStatement ;; 1093 1094 identifier=namespacedIdentifier 1095 -> classExtends ;; 1096 1097 #implements=namespacedIdentifier @ COMMA 1098 -> classImplements ;; 1099 1100 -- error recovery, to understand it you probably have to look at the generated code ;-) 1101 [: bool reported = false; while ( true ) { :] 1102 try/recover(#classStatements=classStatement)* 1103 [: if (yytoken != Token_RBRACE && yytoken != Token_EOF && yytoken != Token_CLOSE_TAG) { 1104 if (!reported) { 1105 reportProblem(Error, QStringLiteral("Unexpected token in class context.")); 1106 reported = true; 1107 } 1108 yylex(); 1109 } else { 1110 break; 1111 } 1112 } :] 1113 RBRACE [: rewind(tokenStream->index() - 2); :] 1114 -> classBody ;; 1115 1116 VAR variable=classVariableDeclaration SEMICOLON 1117 | modifiers=optionalModifiers 1118 ( (propertyType=propertyType | 0) variable=classVariableDeclaration SEMICOLON 1119 | FUNCTION (BIT_AND | 0) methodName=semiReservedIdentifier LPAREN parameters=parameterList RPAREN 1120 ( COLON returnType=returnType | 0) 1121 methodBody=methodBody 1122 | CONST #consts=classConstantDeclaration @ COMMA SEMICOLON 1123 ) 1124 | USE #traits=namespacedIdentifier @ COMMA (imports=traitAliasDeclaration|SEMICOLON) 1125 -> classStatement ;; 1126 1127 LBRACE #statements=traitAliasStatement 1128 @ (SEMICOLON [: if (yytoken == Token_RBRACE) { break; } :]) RBRACE 1129 -> traitAliasDeclaration ;; 1130 1131 importIdentifier=traitAliasIdentifier 1132 -- first/first conflict resolved by LA(2) 1133 -- We can either have a single token (modifier or identifier), or a combination 1134 ( AS (?[: LA(2).kind == Token_SEMICOLON :] 1135 (modifiers=traitVisibilityModifiers | aliasNonModifierIdentifier=reservedNonModifierIdentifier) 1136 | modifiers=traitVisibilityModifiers aliasIdentifier=semiReservedIdentifier 1137 ) 1138 | INSTEADOF #conflictIdentifier=namespacedIdentifier @ COMMA 1139 ) 1140 -> traitAliasStatement ;; 1141 1142 identifier=namespacedIdentifier PAAMAYIM_NEKUDOTAYIM methodIdentifier=semiReservedIdentifier 1143 -> traitAliasIdentifier ;; 1144 1145 SEMICOLON -- abstract method 1146 | LBRACE try/recover(statements=innerStatementList) RBRACE 1147 -> methodBody ;; 1148 1149 #vars=classVariable @ COMMA 1150 -> classVariableDeclaration ;; 1151 1152 variable=variableIdentifier (ASSIGN value=staticScalar | 0) 1153 -> classVariable ;; 1154 1155 PUBLIC [: (*yynode)->modifiers |= ModifierPublic; :] 1156 | PROTECTED [: (*yynode)->modifiers |= ModifierProtected; :] 1157 | PRIVATE [: (*yynode)->modifiers |= ModifierPrivate; :] 1158 | STATIC [: (*yynode)->modifiers |= ModifierStatic; :] 1159 | ABSTRACT [: (*yynode)->modifiers |= ModifierAbstract; :] 1160 | FINAL [: (*yynode)->modifiers |= ModifierFinal; :] 1161 -> traitVisibilityModifiers[ 1162 member variable modifiers: unsigned int; 1163 ] ;; 1164 1165 ( 1166 PUBLIC [: (*yynode)->modifiers |= ModifierPublic; :] 1167 | PROTECTED [: (*yynode)->modifiers |= ModifierProtected; :] 1168 | PRIVATE [: (*yynode)->modifiers |= ModifierPrivate; :] 1169 | STATIC [: (*yynode)->modifiers |= ModifierStatic; :] 1170 | ABSTRACT [: (*yynode)->modifiers |= ModifierAbstract; :] 1171 | FINAL [: (*yynode)->modifiers |= ModifierFinal; :] 1172 | 0 1173 )* 1174 -> optionalModifiers[ 1175 member variable modifiers: unsigned int; 1176 ] ;; 1177 1178 ( 1179 ABSTRACT [: (*yynode)->modifier = AbstractClass; :] 1180 | FINAL [: (*yynode)->modifier = FinalClass; :] 1181 | 0 1182 ) 1183 -> optionalClassModifier[ 1184 member variable modifier: ClassModifier; 1185 ] ;; 1186 1187 1188 1189 1190 1191 ----------------------------------------------------------------- 1192 -- Code segments copied to the implementation (.cpp) file. 1193 -- If existent, kdevelop-pg's current syntax requires this block 1194 -- to occur at the end of the file. 1195 ----------------------------------------------------------------- 1196 1197 [: 1198 1199 #include <QtCore/QDebug> 1200 #include <language/editor/documentrange.h> 1201 1202 namespace Php 1203 { 1204 1205 void Parser::tokenize(const QString& contents, int initialState) 1206 { 1207 m_contents = contents; 1208 Lexer lexer(tokenStream, contents, initialState); 1209 int kind = Parser::Token_EOF; 1210 int lastDocCommentBegin; 1211 int lastDocCommentEnd; 1212 1213 do 1214 { 1215 lastDocCommentBegin = 0; 1216 lastDocCommentEnd = 0; 1217 kind = lexer.nextTokenKind(); 1218 while (kind == Parser::Token_WHITESPACE || kind == Parser::Token_COMMENT || kind == Parser::Token_DOC_COMMENT) { 1219 if (kind == Parser::Token_COMMENT || kind == Parser::Token_DOC_COMMENT) { 1220 extractTodosFromComment(tokenText(lexer.tokenBegin(), lexer.tokenEnd()), lexer.tokenBegin()); 1221 } 1222 if (kind == Parser::Token_DOC_COMMENT) { 1223 lastDocCommentBegin = lexer.tokenBegin(); 1224 lastDocCommentEnd = lexer.tokenEnd(); 1225 } 1226 kind = lexer.nextTokenKind(); 1227 } 1228 if ( !kind ) // when the lexer returns 0, the end of file is reached 1229 { 1230 kind = Parser::Token_EOF; 1231 } 1232 Parser::Token &t = tokenStream->push(); 1233 t.begin = lexer.tokenBegin(); 1234 t.end = lexer.tokenEnd(); 1235 t.kind = kind; 1236 t.docCommentBegin = lastDocCommentBegin; 1237 t.docCommentEnd = lastDocCommentEnd; 1238 //if ( m_debug ) qDebug() << kind << tokenText(t.begin,t.end) << t.begin << t.end; 1239 } 1240 while ( kind != Parser::Token_EOF ); 1241 1242 yylex(); // produce the look ahead token 1243 } 1244 1245 void Parser::extractTodosFromComment(const QString& comment, qint64 startPosition) 1246 { 1247 auto i = m_todoMarkers.globalMatch(comment); 1248 while (i.hasNext()) { 1249 auto match = i.next(); 1250 auto p = reportProblem(Todo, match.captured(1), 0); 1251 if (!p) { 1252 continue; 1253 } 1254 1255 qint64 line = 0; 1256 qint64 column = 0; 1257 tokenStream->locationTable()->positionAt(startPosition, &line, &column); 1258 1259 auto location = p->finalLocation(); 1260 location.setStart(KTextEditor::Cursor(line, column + match.capturedStart(1))); 1261 location.setEnd(KTextEditor::Cursor(line, column + match.capturedEnd(1))); 1262 p->setFinalLocation(location); 1263 }; 1264 } 1265 1266 void Parser::setTodoMarkers(const QStringList& markers) 1267 { 1268 QString pattern = QStringLiteral("^(?:[/\\*\\s]*)(.*(?:"); 1269 bool first = true; 1270 foreach(const QString& marker, markers) { 1271 if (!first) { 1272 pattern += '|'; 1273 } 1274 pattern += QRegularExpression::escape(marker); 1275 first = false; 1276 } 1277 pattern += QStringLiteral(").*?)(?:[/\\*\\s]*)$"); 1278 m_todoMarkers.setPatternOptions(QRegularExpression::MultilineOption); 1279 m_todoMarkers.setPattern(pattern); 1280 } 1281 1282 QString Parser::tokenText(qint64 begin, qint64 end) 1283 { 1284 return m_contents.mid(begin,end-begin+1); 1285 } 1286 1287 1288 KDevelop::ProblemPointer Parser::reportProblem( Parser::ProblemType type, const QString& message, int offset ) 1289 { 1290 qint64 sLine; 1291 qint64 sCol; 1292 qint64 index = tokenStream->index() + offset; 1293 if (index >= tokenStream->size()) { 1294 return {}; 1295 } 1296 tokenStream->startPosition(index, &sLine, &sCol); 1297 qint64 eLine; 1298 qint64 eCol; 1299 tokenStream->endPosition(index, &eLine, &eCol); 1300 auto p = KDevelop::ProblemPointer(new KDevelop::Problem()); 1301 p->setSource(KDevelop::IProblem::Parser); 1302 switch ( type ) { 1303 case Error: 1304 p->setSeverity(KDevelop::IProblem::Error); 1305 break; 1306 case Warning: 1307 p->setSeverity(KDevelop::IProblem::Warning); 1308 break; 1309 case Info: 1310 p->setSeverity(KDevelop::IProblem::Hint); 1311 break; 1312 case Todo: 1313 p->setSeverity(KDevelop::IProblem::Hint); 1314 p->setSource(KDevelop::IProblem::ToDo); 1315 break; 1316 } 1317 p->setDescription(message); 1318 KTextEditor::Range range(sLine, sCol, eLine, eCol + 1); 1319 p->setFinalLocation(KDevelop::DocumentRange(m_currentDocument, range)); 1320 m_problems << p; 1321 return p; 1322 } 1323 1324 1325 // custom error recovery 1326 void Parser::expectedToken(int /*expected*/, qint64 /*where*/, const QString& name) 1327 { 1328 reportProblem( Parser::Error, QStringLiteral("Expected token \"%1\"").arg(name)); 1329 } 1330 1331 void Parser::expectedSymbol(int /*expectedSymbol*/, const QString& name) 1332 { 1333 qint64 line; 1334 qint64 col; 1335 qint64 index = tokenStream->index()-1; 1336 Token &token = tokenStream->at(index); 1337 qCDebug(PARSER) << "token starts at:" << token.begin; 1338 qCDebug(PARSER) << "index is:" << index; 1339 tokenStream->startPosition(index, &line, &col); 1340 QString tokenValue = tokenText(token.begin, token.end); 1341 qint64 eLine; 1342 qint64 eCol; 1343 tokenStream->endPosition(index, &eLine, &eCol); 1344 reportProblem( Parser::Error, 1345 QStringLiteral("Expected symbol \"%1\" (current token: \"%2\" [%3] at %4:%5 - %6:%7)") 1346 .arg(name, 1347 token.kind != 0 ? tokenValue : QStringLiteral("EOF")) 1348 .arg(token.kind) 1349 .arg(line) 1350 .arg(col) 1351 .arg(eLine) 1352 .arg(eCol)); 1353 } 1354 1355 void Parser::setDebug( bool debug ) 1356 { 1357 m_debug = debug; 1358 } 1359 1360 void Parser::setCurrentDocument(KDevelop::IndexedString url) 1361 { 1362 m_currentDocument = url; 1363 } 1364 1365 1366 Parser::ParserState *Parser::copyCurrentState() 1367 { 1368 ParserState *state = new ParserState(); 1369 state->varExpressionState = m_state.varExpressionState; 1370 state->varExpressionIsVariable = m_state.varExpressionIsVariable; 1371 return state; 1372 } 1373 1374 void Parser::restoreState( Parser::ParserState* state) 1375 { 1376 m_state.varExpressionState = state->varExpressionState; 1377 m_state.varExpressionIsVariable = state->varExpressionIsVariable; 1378 } 1379 1380 } // end of namespace Php 1381 1382 :] 1383 1384 -- kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on; auto-insert-doxygen on; mode KDevelop-PG[-Qt]