Added patch for #1434245
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
1 /***********************************************************************************************************************************
2  * Copyright (c) 2002 www.phpeclipse.de All rights reserved. This program and the accompanying material are made available under the
3  * terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html
5  *
6  * Contributors: www.phpeclipse.de
7  **********************************************************************************************************************************/
8 package net.sourceforge.phpdt.internal.compiler.parser;
9
10 import java.util.ArrayList;
11 import java.util.HashMap;
12 import java.util.HashSet;
13
14 import net.sourceforge.phpdt.core.compiler.CharOperation;
15 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
16 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
17 import net.sourceforge.phpdt.internal.compiler.ast.AND_AND_Expression;
18 import net.sourceforge.phpdt.internal.compiler.ast.ASTNode;
19 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
20 import net.sourceforge.phpdt.internal.compiler.ast.BinaryExpression;
21 import net.sourceforge.phpdt.internal.compiler.ast.Block;
22 import net.sourceforge.phpdt.internal.compiler.ast.BreakStatement;
23 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
24 import net.sourceforge.phpdt.internal.compiler.ast.ConditionalExpression;
25 import net.sourceforge.phpdt.internal.compiler.ast.ContinueStatement;
26 import net.sourceforge.phpdt.internal.compiler.ast.EqualExpression;
27 import net.sourceforge.phpdt.internal.compiler.ast.Expression;
28 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
29 import net.sourceforge.phpdt.internal.compiler.ast.FieldReference;
30 import net.sourceforge.phpdt.internal.compiler.ast.IfStatement;
31 import net.sourceforge.phpdt.internal.compiler.ast.ImportReference;
32 import net.sourceforge.phpdt.internal.compiler.ast.InstanceOfExpression;
33 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
34 import net.sourceforge.phpdt.internal.compiler.ast.OR_OR_Expression;
35 import net.sourceforge.phpdt.internal.compiler.ast.OperatorIds;
36 import net.sourceforge.phpdt.internal.compiler.ast.ReturnStatement;
37 import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference;
38 import net.sourceforge.phpdt.internal.compiler.ast.Statement;
39 import net.sourceforge.phpdt.internal.compiler.ast.StringLiteral;
40 import net.sourceforge.phpdt.internal.compiler.ast.StringLiteralDQ;
41 import net.sourceforge.phpdt.internal.compiler.ast.StringLiteralSQ;
42 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
43 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
44 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
45 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
46 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
47 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
48 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
49 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
50 import net.sourceforge.phpdt.internal.compiler.util.Util;
51 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
52 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
53 import net.sourceforge.phpeclipse.ui.overlaypages.ProjectPrefUtil;
54
55 import org.eclipse.core.resources.IFile;
56 import org.eclipse.core.resources.IProject;
57 import org.eclipse.core.resources.IResource;
58 import org.eclipse.core.runtime.IPath;
59
60 public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicInformation {
61         protected final static int StackIncrement = 255;
62
63         protected int stateStackTop;
64
65         // protected int[] stack = new int[StackIncrement];
66
67         public int firstToken; // handle for multiple parsing goals
68
69         public int lastAct; // handle for multiple parsing goals
70
71         // protected RecoveredElement currentElement;
72
73         public static boolean VERBOSE_RECOVERY = false;
74
75         protected boolean diet = false; // tells the scanner to jump over some
76
77         /**
78          * the PHP token scanner
79          */
80         public Scanner scanner;
81
82         int token;
83
84         protected int modifiers;
85
86         protected int modifiersSourceStart;
87
88         protected Parser(ProblemReporter problemReporter) {
89                 this.problemReporter = problemReporter;
90                 this.options = problemReporter.options;
91                 this.token = TokenNameEOF;
92                 this.initializeScanner();
93         }
94
95         public void setFileToParse(IFile fileToParse) {
96                 this.token = TokenNameEOF;
97                 this.initializeScanner();
98         }
99
100         /**
101          * ClassDeclaration Constructor.
102          *
103          * @param s
104          * @param sess
105          *          Description of Parameter
106          * @see
107          */
108         public Parser(IFile fileToParse) {
109                 // if (keywordMap == null) {
110                 // keywordMap = new HashMap();
111                 // for (int i = 0; i < PHP_KEYWORS.length; i++) {
112                 // keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
113                 // }
114                 // }
115                 // this.currentPHPString = 0;
116                 // PHPParserSuperclass.fileToParse = fileToParse;
117                 // this.phpList = null;
118                 this.includesList = null;
119                 // this.str = "";
120                 this.token = TokenNameEOF;
121                 // this.chIndx = 0;
122                 // this.rowCount = 1;
123                 // this.columnCount = 0;
124                 // this.phpEnd = false;
125                 // getNextToken();
126                 this.initializeScanner();
127         }
128
129         public void initializeScanner() {
130                 this.scanner = new Scanner(false /* comment */, false /* whitespace */, this.options
131                                 .getSeverity(CompilerOptions.NonExternalizedString) != ProblemSeverities.Ignore /* nls */, false, false,
132                                 this.options.taskTags/* taskTags */, this.options.taskPriorites/* taskPriorities */, true/* isTaskCaseSensitive */);
133         }
134
135         /**
136          * Create marker for the parse error
137          */
138         // private void setMarker(String message, int charStart, int charEnd, int
139         // errorLevel) {
140         // setMarker(fileToParse, message, charStart, charEnd, errorLevel);
141         // }
142         /**
143          * This method will throw the SyntaxError. It will add the good lines and
144          * columns to the Error
145          *
146          * @param error
147          *          the error message
148          * @throws SyntaxError
149          *           the error raised
150          */
151         private void throwSyntaxError(String error) {
152                 int problemStartPosition = scanner.getCurrentTokenStartPosition();
153                 int problemEndPosition = scanner.getCurrentTokenEndPosition() + 1;
154                 if (scanner.source.length <= problemEndPosition && problemEndPosition > 0) {
155                         problemEndPosition = scanner.source.length - 1;
156                         if (problemStartPosition > 0 && problemStartPosition >= problemEndPosition && problemEndPosition > 0) {
157                                 problemStartPosition = problemEndPosition - 1;
158                         }
159                 }
160                 throwSyntaxError(error, problemStartPosition, problemEndPosition);
161         }
162
163         /**
164          * This method will throw the SyntaxError. It will add the good lines and
165          * columns to the Error
166          *
167          * @param error
168          *          the error message
169          * @throws SyntaxError
170          *           the error raised
171          */
172         // private void throwSyntaxError(String error, int startRow) {
173         // throw new SyntaxError(startRow, 0, " ", error);
174         // }
175         private void throwSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
176                 if (referenceContext != null) {
177                         problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext,
178                                         compilationUnit.compilationResult);
179                 }
180                 throw new SyntaxError(1, 0, " ", error);
181         }
182
183         private void reportSyntaxError(String error) {
184                 int problemStartPosition = scanner.getCurrentTokenStartPosition();
185                 int problemEndPosition = scanner.getCurrentTokenEndPosition();
186                 reportSyntaxError(error, problemStartPosition, problemEndPosition + 1);
187         }
188
189         private void reportSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
190                 if (referenceContext != null) {
191                         problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext,
192                                         compilationUnit.compilationResult);
193                 }
194         }
195
196         // private void reportSyntaxWarning(String error, int problemStartPosition,
197         // int problemEndPosition) {
198         // if (referenceContext != null) {
199         // problemReporter.phpParsingWarning(new String[] { error },
200         // problemStartPosition, problemEndPosition, referenceContext,
201         // compilationUnit.compilationResult);
202         // }
203         // }
204
205         /**
206          * gets the next token from input
207          */
208         private void getNextToken() {
209                 try {
210                         token = scanner.getNextToken();
211                         if (Scanner.DEBUG) {
212                                 int currentEndPosition = scanner.getCurrentTokenEndPosition();
213                                 int currentStartPosition = scanner.getCurrentTokenStartPosition();
214                                 System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
215                                 System.out.println(scanner.toStringAction(token));
216                         }
217                 } catch (InvalidInputException e) {
218                         token = TokenNameERROR;
219                         String detailedMessage = e.getMessage();
220
221                         if (detailedMessage == Scanner.UNTERMINATED_STRING) {
222                                 throwSyntaxError("Unterminated string.");
223                         } else if (detailedMessage == Scanner.UNTERMINATED_COMMENT) {
224                                 throwSyntaxError("Unterminated commment.");
225                         }
226                 }
227                 return;
228         }
229
230         public void init(String s) {
231                 // this.str = s;
232                 this.token = TokenNameEOF;
233                 this.includesList = new ArrayList();
234                 // this.chIndx = 0;
235                 // this.rowCount = 1;
236                 // this.columnCount = 0;
237                 // this.phpEnd = false;
238                 // this.phpMode = false;
239                 /* scanner initialization */
240                 scanner.setSource(s.toCharArray());
241                 scanner.setPHPMode(false);
242                 astPtr = 0;
243         }
244
245         protected void initialize(boolean phpMode) {
246                 initialize(phpMode, null);
247         }
248
249         protected void initialize(boolean phpMode, IdentifierIndexManager indexManager) {
250                 compilationUnit = null;
251                 referenceContext = null;
252                 this.includesList = new ArrayList();
253                 // this.indexManager = indexManager;
254                 // this.str = "";
255                 this.token = TokenNameEOF;
256                 // this.chIndx = 0;
257                 // this.rowCount = 1;
258                 // this.columnCount = 0;
259                 // this.phpEnd = false;
260                 // this.phpMode = phpMode;
261                 scanner.setPHPMode(phpMode);
262                 astPtr = 0;
263         }
264
265         /**
266          * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt;
267          * &lt;/body&gt;'
268          */
269         public void parse(String s) {
270                 parse(s, null);
271         }
272
273         /**
274          * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt;
275          * &lt;/body&gt;'
276          */
277         public void parse(String s, HashMap variables) {
278                 fMethodVariables = variables;
279                 fStackUnassigned = new ArrayList();
280                 init(s);
281                 parse();
282         }
283
284         /**
285          * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt;
286          * &lt;/body&gt;'
287          */
288         protected void parse() {
289                 if (scanner.compilationUnit != null) {
290                         IResource resource = scanner.compilationUnit.getResource();
291                         if (resource != null && resource instanceof IFile) {
292                                 // set the package name
293                                 consumePackageDeclarationName((IFile) resource);
294                         }
295                 }
296                 getNextToken();
297                 do {
298                         try {
299                                 if (token != TokenNameEOF && token != TokenNameERROR) {
300                                         statementList();
301                                 }
302                                 if (token != TokenNameEOF) {
303                                         if (token == TokenNameERROR) {
304                                                 throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
305                                         }
306                                         if (token == TokenNameRPAREN) {
307                                                 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
308                                         }
309                                         if (token == TokenNameRBRACE) {
310                                                 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
311                                         }
312                                         if (token == TokenNameRBRACKET) {
313                                                 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
314                                         }
315                                         if (token == TokenNameLPAREN) {
316                                                 throwSyntaxError("Read character '('; end-of-file not reached.");
317                                         }
318                                         if (token == TokenNameLBRACE) {
319                                                 throwSyntaxError("Read character '{';  end-of-file not reached.");
320                                         }
321                                         if (token == TokenNameLBRACKET) {
322                                                 throwSyntaxError("Read character '[';  end-of-file not reached.");
323                                         }
324                                         throwSyntaxError("End-of-file not reached.");
325                                 }
326                                 break;
327                         } catch (SyntaxError syntaxError) {
328                                 // syntaxError.printStackTrace();
329                                 break;
330                         }
331                 } while (true);
332
333                 endParse(0);
334         }
335
336         /**
337          * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt;
338          * &lt;/body&gt;'
339          */
340         public void parseFunction(String s, HashMap variables) {
341                 init(s);
342                 scanner.phpMode = true;
343                 parseFunction(variables);
344         }
345
346         /**
347          * Parses a string with php tags i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt;
348          * &lt;/body&gt;'
349          */
350         protected void parseFunction(HashMap variables) {
351                 getNextToken();
352                 boolean hasModifiers = member_modifiers();
353                 if (token == TokenNamefunction) {
354                         if (!hasModifiers) {
355                                 checkAndSetModifiers(AccPublic);
356                         }
357                         this.fMethodVariables = variables;
358
359                         MethodDeclaration methodDecl = new MethodDeclaration(null);
360                         methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
361                         methodDecl.modifiers = this.modifiers;
362                         methodDecl.type = MethodDeclaration.METHOD_DEFINITION;
363                         try {
364                                 getNextToken();
365                                 functionDefinition(methodDecl);
366                         } catch (SyntaxError sytaxErr1) {
367                                 return;
368                         } finally {
369                                 int sourceEnd = methodDecl.sourceEnd;
370                                 if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) {
371                                         sourceEnd = methodDecl.declarationSourceStart + 1;
372                                 }
373                                 methodDecl.sourceEnd = sourceEnd;
374                                 methodDecl.declarationSourceEnd = sourceEnd;
375                         }
376                 }
377         }
378
379         protected CompilationUnitDeclaration endParse(int act) {
380
381                 this.lastAct = act;
382
383                 // if (currentElement != null) {
384                 // currentElement.topElement().updateParseTree();
385                 // if (VERBOSE_RECOVERY) {
386                 // System.out.print(Util.bind("parser.syntaxRecovery")); //$NON-NLS-1$
387                 // System.out.println("--------------------------"); //$NON-NLS-1$
388                 // System.out.println(compilationUnit);
389                 // System.out.println("----------------------------------"); //$NON-NLS-1$
390                 // }
391                 // } else {
392                 if (diet & VERBOSE_RECOVERY) {
393                         System.out.print(Util.bind("parser.regularParse")); //$NON-NLS-1$
394                         System.out.println("--------------------------"); //$NON-NLS-1$
395                         System.out.println(compilationUnit);
396                         System.out.println("----------------------------------"); //$NON-NLS-1$
397                 }
398                 // }
399                 if (scanner.recordLineSeparator) {
400                         compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
401                 }
402                 if (scanner.taskTags != null) {
403                         for (int i = 0; i < scanner.foundTaskCount; i++) {
404                                 problemReporter().task(new String(scanner.foundTaskTags[i]), new String(scanner.foundTaskMessages[i]),
405                                                 scanner.foundTaskPriorities[i] == null ? null : new String(scanner.foundTaskPriorities[i]),
406                                                 scanner.foundTaskPositions[i][0], scanner.foundTaskPositions[i][1]);
407                         }
408                 }
409                 compilationUnit.imports = new ImportReference[includesList.size()];
410                 for (int i = 0; i < includesList.size(); i++) {
411                         compilationUnit.imports[i] = (ImportReference) includesList.get(i);
412                 }
413                 return compilationUnit;
414         }
415
416         private Block statementList() {
417                 boolean branchStatement = false;
418                 Statement statement;
419                 int blockStart = scanner.getCurrentTokenStartPosition();
420                 ArrayList blockStatements = new ArrayList();
421                 do {
422                         try {
423                                 statement = statement();
424                                 blockStatements.add(statement);
425                                 if (token == TokenNameEOF) {
426                                         return null;
427                                 }
428                                 if (branchStatement && statement != null) {
429                                         // reportSyntaxError("Unreachable code", statement.sourceStart,
430                                         // statement.sourceEnd);
431                                         if (! (statement instanceof BreakStatement)) {
432                                                 /* don't give an error for break statement following return statement
433                                                 Technically it's unreachable code, but in switch-case it's recommended to
434                                                 avoid accidental fall-through later when editing the code */
435                                                 problemReporter.unreachableCode(new String(scanner.getCurrentIdentifierSource()), statement.sourceStart,
436                                                         statement.sourceEnd, referenceContext, compilationUnit.compilationResult);
437                                         }
438                                 }
439                                 if ((token == TokenNameRBRACE) || (token == TokenNamecase) || (token == TokenNamedefault) || (token == TokenNameelse)
440                                                 || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor)
441                                                 || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch)
442                                                 || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) {
443                                         return createBlock(blockStart, blockStatements);
444                                 }
445                                 branchStatement = checkUnreachableStatements(statement);
446                         } catch (SyntaxError sytaxErr1) {
447                                 // if an error occured,
448                                 // try to find keywords
449                                 // to parse the rest of the string
450                                 boolean tokenize = scanner.tokenizeStrings;
451                                 if (!tokenize) {
452                                         scanner.tokenizeStrings = true;
453                                 }
454                                 try {
455                                         while (token != TokenNameEOF) {
456                                                 if ((token == TokenNameRBRACE) || (token == TokenNamecase) || (token == TokenNamedefault) || (token == TokenNameelse)
457                                                                 || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor)
458                                                                 || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch)
459                                                                 || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) {
460                                                         return createBlock(blockStart, blockStatements);
461                                                 }
462                                                 if (token == TokenNameif || token == TokenNameswitch || token == TokenNamefor || token == TokenNamewhile
463                                                                 || token == TokenNamedo || token == TokenNameforeach || token == TokenNamecontinue || token == TokenNamebreak
464                                                                 || token == TokenNamereturn || token == TokenNameexit || token == TokenNameecho || token == TokenNameECHO_INVISIBLE
465                                                                 || token == TokenNameglobal || token == TokenNamestatic || token == TokenNameunset || token == TokenNamefunction
466                                                                 || token == TokenNamedeclare || token == TokenNametry || token == TokenNamecatch || token == TokenNamethrow
467                                                                 || token == TokenNamefinal || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
468                                                         break;
469                                                 }
470                                                 // System.out.println(scanner.toStringAction(token));
471                                                 getNextToken();
472                                                 // System.out.println(scanner.toStringAction(token));
473                                         }
474                                         if (token == TokenNameEOF) {
475                                                 throw sytaxErr1;
476                                         }
477                                 } finally {
478                                         scanner.tokenizeStrings = tokenize;
479                                 }
480                         }
481                 } while (true);
482         }
483
484         /**
485          * @param statement
486          * @return
487          */
488         private boolean checkUnreachableStatements(Statement statement) {
489                 if (statement instanceof ReturnStatement || statement instanceof ContinueStatement || statement instanceof BreakStatement) {
490                         return true;
491                 } else if (statement instanceof IfStatement && ((IfStatement) statement).checkUnreachable) {
492                         return true;
493                 }
494                 return false;
495         }
496
497         /**
498          * @param blockStart
499          * @param blockStatements
500          * @return
501          */
502         private Block createBlock(int blockStart, ArrayList blockStatements) {
503                 int blockEnd = scanner.getCurrentTokenEndPosition();
504                 Block b = Block.EmptyWith(blockStart, blockEnd);
505                 b.statements = new Statement[blockStatements.size()];
506                 blockStatements.toArray(b.statements);
507                 return b;
508         }
509
510         private void functionBody(MethodDeclaration methodDecl) {
511                 // '{' [statement-list] '}'
512                 if (token == TokenNameLBRACE) {
513                         getNextToken();
514                 } else {
515                         methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1;
516                         throwSyntaxError("'{' expected in compound-statement.");
517                 }
518                 if (token != TokenNameRBRACE) {
519                         statementList();
520                 }
521                 if (token == TokenNameRBRACE) {
522                         methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
523                         getNextToken();
524                 } else {
525                         methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1;
526                         throwSyntaxError("'}' expected in compound-statement.");
527                 }
528         }
529
530         private Statement statement() {
531                 Statement statement = null;
532                 Expression expression;
533                 int sourceStart = scanner.getCurrentTokenStartPosition();
534                 int sourceEnd;
535                 if (token == TokenNameif) {
536                         // T_IF '(' expr ')' statement elseif_list else_single
537                         // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list
538                         // new_else_single T_ENDIF ';'
539                         getNextToken();
540                         if (token == TokenNameLPAREN) {
541                                 getNextToken();
542                         } else {
543                                 throwSyntaxError("'(' expected after 'if' keyword.");
544                         }
545                         expression = expr();
546                         if (token == TokenNameRPAREN) {
547                                 getNextToken();
548                         } else {
549                                 throwSyntaxError("')' expected after 'if' condition.");
550                         }
551                         // create basic IfStatement
552                         IfStatement ifStatement = new IfStatement(expression, null, null, sourceStart, -1);
553                         if (token == TokenNameCOLON) {
554                                 getNextToken();
555                                 ifStatementColon(ifStatement);
556                         } else {
557                                 ifStatement(ifStatement);
558                         }
559                         return ifStatement;
560                 } else if (token == TokenNameswitch) {
561                         getNextToken();
562                         if (token == TokenNameLPAREN) {
563                                 getNextToken();
564                         } else {
565                                 throwSyntaxError("'(' expected after 'switch' keyword.");
566                         }
567                         expr();
568                         if (token == TokenNameRPAREN) {
569                                 getNextToken();
570                         } else {
571                                 throwSyntaxError("')' expected after 'switch' condition.");
572                         }
573                         switchStatement();
574                         return statement;
575                 } else if (token == TokenNamefor) {
576                         getNextToken();
577                         if (token == TokenNameLPAREN) {
578                                 getNextToken();
579                         } else {
580                                 throwSyntaxError("'(' expected after 'for' keyword.");
581                         }
582                         if (token == TokenNameSEMICOLON) {
583                                 getNextToken();
584                         } else {
585                                 expressionList();
586                                 if (token == TokenNameSEMICOLON) {
587                                         getNextToken();
588                                 } else {
589                                         throwSyntaxError("';' expected after 'for'.");
590                                 }
591                         }
592                         if (token == TokenNameSEMICOLON) {
593                                 getNextToken();
594                         } else {
595                                 expressionList();
596                                 if (token == TokenNameSEMICOLON) {
597                                         getNextToken();
598                                 } else {
599                                         throwSyntaxError("';' expected after 'for'.");
600                                 }
601                         }
602                         if (token == TokenNameRPAREN) {
603                                 getNextToken();
604                         } else {
605                                 expressionList();
606                                 if (token == TokenNameRPAREN) {
607                                         getNextToken();
608                                 } else {
609                                         throwSyntaxError("')' expected after 'for'.");
610                                 }
611                         }
612                         forStatement();
613                         return statement;
614                 } else if (token == TokenNamewhile) {
615                         getNextToken();
616                         if (token == TokenNameLPAREN) {
617                                 getNextToken();
618                         } else {
619                                 throwSyntaxError("'(' expected after 'while' keyword.");
620                         }
621                         expr();
622                         if (token == TokenNameRPAREN) {
623                                 getNextToken();
624                         } else {
625                                 throwSyntaxError("')' expected after 'while' condition.");
626                         }
627                         whileStatement();
628                         return statement;
629                 } else if (token == TokenNamedo) {
630                         getNextToken();
631                         if (token == TokenNameLBRACE) {
632                                 getNextToken();
633                                 if (token != TokenNameRBRACE) {
634                                         statementList();
635                                 }
636                                 if (token == TokenNameRBRACE) {
637                                         getNextToken();
638                                 } else {
639                                         throwSyntaxError("'}' expected after 'do' keyword.");
640                                 }
641                         } else {
642                                 statement();
643                         }
644                         if (token == TokenNamewhile) {
645                                 getNextToken();
646                                 if (token == TokenNameLPAREN) {
647                                         getNextToken();
648                                 } else {
649                                         throwSyntaxError("'(' expected after 'while' keyword.");
650                                 }
651                                 expr();
652                                 if (token == TokenNameRPAREN) {
653                                         getNextToken();
654                                 } else {
655                                         throwSyntaxError("')' expected after 'while' condition.");
656                                 }
657                         } else {
658                                 throwSyntaxError("'while' expected after 'do' keyword.");
659                         }
660                         if (token == TokenNameSEMICOLON) {
661                                 getNextToken();
662                         } else {
663                                 if (token != TokenNameINLINE_HTML) {
664                                         throwSyntaxError("';' expected after do-while statement.");
665                                 }
666                                 getNextToken();
667                         }
668                         return statement;
669                 } else if (token == TokenNameforeach) {
670                         getNextToken();
671                         if (token == TokenNameLPAREN) {
672                                 getNextToken();
673                         } else {
674                                 throwSyntaxError("'(' expected after 'foreach' keyword.");
675                         }
676                         expr();
677                         if (token == TokenNameas) {
678                                 getNextToken();
679                         } else {
680                                 throwSyntaxError("'as' expected after 'foreach' exxpression.");
681                         }
682                         // variable();
683                         foreach_variable();
684                         foreach_optional_arg();
685                         if (token == TokenNameEQUAL_GREATER) {
686                                 getNextToken();
687                                 variable(false, false);
688                         }
689                         if (token == TokenNameRPAREN) {
690                                 getNextToken();
691                         } else {
692                                 throwSyntaxError("')' expected after 'foreach' expression.");
693                         }
694                         foreachStatement();
695                         return statement;
696                 } else if (token == TokenNamebreak) {
697                         expression = null;
698                         getNextToken();
699                         if (token != TokenNameSEMICOLON) {
700                                 expression = expr();
701                         }
702                         if (token == TokenNameSEMICOLON) {
703                                 sourceEnd = scanner.getCurrentTokenEndPosition();
704                                 getNextToken();
705                         } else {
706                                 if (token != TokenNameINLINE_HTML) {
707                                         throwSyntaxError("';' expected after 'break'.");
708                                 }
709                                 sourceEnd = scanner.getCurrentTokenEndPosition();
710                                 getNextToken();
711                         }
712                         return new BreakStatement(null, sourceStart, sourceEnd);
713                 } else if (token == TokenNamecontinue) {
714                         expression = null;
715                         getNextToken();
716                         if (token != TokenNameSEMICOLON) {
717                                 expression = expr();
718                         }
719                         if (token == TokenNameSEMICOLON) {
720                                 sourceEnd = scanner.getCurrentTokenEndPosition();
721                                 getNextToken();
722                         } else {
723                                 if (token != TokenNameINLINE_HTML) {
724                                         throwSyntaxError("';' expected after 'continue'.");
725                                 }
726                                 sourceEnd = scanner.getCurrentTokenEndPosition();
727                                 getNextToken();
728                         }
729                         return new ContinueStatement(null, sourceStart, sourceEnd);
730                 } else if (token == TokenNamereturn) {
731                         expression = null;
732                         getNextToken();
733                         if (token != TokenNameSEMICOLON) {
734                                 expression = expr();
735                         }
736                         if (token == TokenNameSEMICOLON) {
737                                 sourceEnd = scanner.getCurrentTokenEndPosition();
738                                 getNextToken();
739                         } else {
740                                 if (token != TokenNameINLINE_HTML) {
741                                         throwSyntaxError("';' expected after 'return'.");
742                                 }
743                                 sourceEnd = scanner.getCurrentTokenEndPosition();
744                                 getNextToken();
745                         }
746                         return new ReturnStatement(expression, sourceStart, sourceEnd);
747                 } else if (token == TokenNameecho) {
748                         getNextToken();
749                         expressionList();
750                         if (token == TokenNameSEMICOLON) {
751                                 getNextToken();
752                         } else {
753                                 if (token != TokenNameINLINE_HTML) {
754                                         throwSyntaxError("';' expected after 'echo' statement.");
755                                 }
756                                 getNextToken();
757                         }
758                         return statement;
759                 } else if (token == TokenNameECHO_INVISIBLE) {
760                         // 0-length token directly after PHP short tag &lt;?=
761                         getNextToken();
762                         expressionList();
763                         if (token == TokenNameSEMICOLON) {
764                                 getNextToken();
765                                 // if (token != TokenNameINLINE_HTML) {
766                                 // // TODO should this become a configurable warning?
767                                 // reportSyntaxError("Probably '?>' expected after PHP short tag
768                                 // expression (only the first expression will be echoed).");
769                                 // }
770                         } else {
771                                 if (token != TokenNameINLINE_HTML) {
772                                         throwSyntaxError("';' expected after PHP short tag '<?=' expression.");
773                                 }
774                                 getNextToken();
775                         }
776                         return statement;
777                 } else if (token == TokenNameINLINE_HTML) {
778                         getNextToken();
779                         return statement;
780                 } else if (token == TokenNameglobal) {
781                         getNextToken();
782                         global_var_list();
783                         if (token == TokenNameSEMICOLON) {
784                                 getNextToken();
785                         } else {
786                                 if (token != TokenNameINLINE_HTML) {
787                                         throwSyntaxError("';' expected after 'global' statement.");
788                                 }
789                                 getNextToken();
790                         }
791                         return statement;
792                 } else if (token == TokenNamestatic) {
793                         getNextToken();
794                         static_var_list();
795                         if (token == TokenNameSEMICOLON) {
796                                 getNextToken();
797                         } else {
798                                 if (token != TokenNameINLINE_HTML) {
799                                         throwSyntaxError("';' expected after 'static' statement.");
800                                 }
801                                 getNextToken();
802                         }
803                         return statement;
804                 } else if (token == TokenNameunset) {
805                         getNextToken();
806                         if (token == TokenNameLPAREN) {
807                                 getNextToken();
808                         } else {
809                                 throwSyntaxError("'(' expected after 'unset' statement.");
810                         }
811                         unset_variables();
812                         if (token == TokenNameRPAREN) {
813                                 getNextToken();
814                         } else {
815                                 throwSyntaxError("')' expected after 'unset' statement.");
816                         }
817                         if (token == TokenNameSEMICOLON) {
818                                 getNextToken();
819                         } else {
820                                 if (token != TokenNameINLINE_HTML) {
821                                         throwSyntaxError("';' expected after 'unset' statement.");
822                                 }
823                                 getNextToken();
824                         }
825                         return statement;
826                 } else if (token == TokenNamefunction) {
827                         MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
828                         methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
829                         methodDecl.modifiers = AccDefault;
830                         methodDecl.type = MethodDeclaration.FUNCTION_DEFINITION;
831                         try {
832                                 getNextToken();
833                                 functionDefinition(methodDecl);
834                         } finally {
835                                 sourceEnd = methodDecl.sourceEnd;
836                                 if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) {
837                                         sourceEnd = methodDecl.declarationSourceStart + 1;
838                                 }
839                                 methodDecl.declarationSourceEnd = sourceEnd;
840                                 methodDecl.sourceEnd = sourceEnd;
841                         }
842                         return statement;
843                 } else if (token == TokenNamedeclare) {
844                         // T_DECLARE '(' declare_list ')' declare_statement
845                         getNextToken();
846                         if (token != TokenNameLPAREN) {
847                                 throwSyntaxError("'(' expected in 'declare' statement.");
848                         }
849                         getNextToken();
850                         declare_list();
851                         if (token != TokenNameRPAREN) {
852                                 throwSyntaxError("')' expected in 'declare' statement.");
853                         }
854                         getNextToken();
855                         declare_statement();
856                         return statement;
857                 } else if (token == TokenNametry) {
858                         getNextToken();
859                         if (token != TokenNameLBRACE) {
860                                 throwSyntaxError("'{' expected in 'try' statement.");
861                         }
862                         getNextToken();
863                         statementList();
864                         if (token != TokenNameRBRACE) {
865                                 throwSyntaxError("'}' expected in 'try' statement.");
866                         }
867                         getNextToken();
868                         return statement;
869                 } else if (token == TokenNamecatch) {
870                         getNextToken();
871                         if (token != TokenNameLPAREN) {
872                                 throwSyntaxError("'(' expected in 'catch' statement.");
873                         }
874                         getNextToken();
875                         fully_qualified_class_name();
876                         if (token != TokenNameVariable) {
877                                 throwSyntaxError("Variable expected in 'catch' statement.");
878                         }
879                         addVariableSet();
880                         getNextToken();
881                         if (token != TokenNameRPAREN) {
882                                 throwSyntaxError("')' expected in 'catch' statement.");
883                         }
884                         getNextToken();
885                         if (token != TokenNameLBRACE) {
886                                 throwSyntaxError("'{' expected in 'catch' statement.");
887                         }
888                         getNextToken();
889                         if (token != TokenNameRBRACE) {
890                                 statementList();
891                                 if (token != TokenNameRBRACE) {
892                                         throwSyntaxError("'}' expected in 'catch' statement.");
893                                 }
894                         }
895                         getNextToken();
896                         additional_catches();
897                         return statement;
898                 } else if (token == TokenNamethrow) {
899                         getNextToken();
900                         expr();
901                         if (token == TokenNameSEMICOLON) {
902                                 getNextToken();
903                         } else {
904                                 throwSyntaxError("';' expected after 'throw' exxpression.");
905                         }
906                         return statement;
907                 } else if (token == TokenNamefinal || token == TokenNameabstract || token == TokenNameclass || token == TokenNameinterface) {
908                         try {
909                                 TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
910                                 typeDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
911                                 typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
912                                 typeDecl.name = new char[] { ' ' };
913                                 // default super class
914                                 typeDecl.superclass = new SingleTypeReference(TypeConstants.OBJECT, 0);
915                                 compilationUnit.types.add(typeDecl);
916                                 pushOnAstStack(typeDecl);
917                                 unticked_class_declaration_statement(typeDecl);
918                         } finally {
919                                 // reduce stack:
920                                 astPtr--;
921                                 astLengthPtr--;
922                         }
923                         return statement;
924                         // } else {
925                         // throwSyntaxError("Unexpected keyword '" + keyword + "'");
926                 } else if (token == TokenNameLBRACE) {
927                         getNextToken();
928                         if (token != TokenNameRBRACE) {
929                                 statement = statementList();
930                         }
931                         if (token == TokenNameRBRACE) {
932                                 getNextToken();
933                                 return statement;
934                         } else {
935                                 throwSyntaxError("'}' expected.");
936                         }
937                 } else {
938                         if (token != TokenNameSEMICOLON) {
939                                 expr();
940                         }
941                         if (token == TokenNameSEMICOLON) {
942                                 getNextToken();
943                                 return statement;
944                         } else {
945                                 if (token == TokenNameRBRACE) {
946                                         reportSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
947                                 } else {
948                                         if (token != TokenNameINLINE_HTML && token != TokenNameEOF) {
949                                                 throwSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
950                                         }
951                                         getNextToken();
952                                 }
953                         }
954                 }
955                 // may be null
956                 return statement;
957         }
958
959         private void declare_statement() {
960                 // statement
961                 // | ':' inner_statement_list T_ENDDECLARE ';'
962                 // ;
963                 if (token == TokenNameCOLON) {
964                         getNextToken();
965                         // TODO: implement inner_statement_list();
966                         statementList();
967                         if (token != TokenNameenddeclare) {
968                                 throwSyntaxError("'enddeclare' expected in 'declare' statement.");
969                         }
970                         getNextToken();
971                         if (token != TokenNameSEMICOLON) {
972                                 throwSyntaxError("';' expected after 'enddeclare' keyword.");
973                         }
974                         getNextToken();
975                 } else {
976                         statement();
977                 }
978         }
979
980         private void declare_list() {
981                 // T_STRING '=' static_scalar
982                 // | declare_list ',' T_STRING '=' static_scalar
983                 while (true) {
984                         if (token != TokenNameIdentifier) {
985                                 throwSyntaxError("Identifier expected in 'declare' list.");
986                         }
987                         getNextToken();
988                         if (token != TokenNameEQUAL) {
989                                 throwSyntaxError("'=' expected in 'declare' list.");
990                         }
991                         getNextToken();
992                         static_scalar();
993                         if (token != TokenNameCOMMA) {
994                                 break;
995                         }
996                         getNextToken();
997                 }
998         }
999
1000         private void additional_catches() {
1001                 while (token == TokenNamecatch) {
1002                         getNextToken();
1003                         if (token != TokenNameLPAREN) {
1004                                 throwSyntaxError("'(' expected in 'catch' statement.");
1005                         }
1006                         getNextToken();
1007                         fully_qualified_class_name();
1008                         if (token != TokenNameVariable) {
1009                                 throwSyntaxError("Variable expected in 'catch' statement.");
1010                         }
1011                         addVariableSet();
1012                         getNextToken();
1013                         if (token != TokenNameRPAREN) {
1014                                 throwSyntaxError("')' expected in 'catch' statement.");
1015                         }
1016                         getNextToken();
1017                         if (token != TokenNameLBRACE) {
1018                                 throwSyntaxError("'{' expected in 'catch' statement.");
1019                         }
1020                         getNextToken();
1021                         if (token != TokenNameRBRACE) {
1022                                 statementList();
1023                         }
1024                         if (token != TokenNameRBRACE) {
1025                                 throwSyntaxError("'}' expected in 'catch' statement.");
1026                         }
1027                         getNextToken();
1028                 }
1029         }
1030
1031         private void foreach_variable() {
1032                 // w_variable
1033                 // | '&' w_variable
1034                 if (token == TokenNameAND) {
1035                         getNextToken();
1036                 }
1037                 w_variable(true);
1038         }
1039
1040         private void foreach_optional_arg() {
1041                 // /* empty */
1042                 // | T_DOUBLE_ARROW foreach_variable
1043                 if (token == TokenNameEQUAL_GREATER) {
1044                         getNextToken();
1045                         foreach_variable();
1046                 }
1047         }
1048
1049         private void global_var_list() {
1050                 // global_var_list:
1051                 // global_var_list ',' global_var
1052                 // | global_var
1053                 HashSet set = peekVariableSet();
1054                 while (true) {
1055                         global_var(set);
1056                         if (token != TokenNameCOMMA) {
1057                                 break;
1058                         }
1059                         getNextToken();
1060                 }
1061         }
1062
1063         private void global_var(HashSet set) {
1064                 // global_var:
1065                 // T_VARIABLE
1066                 // | '$' r_variable
1067                 // | '$' '{' expr '}'
1068                 if (token == TokenNameVariable) {
1069                         if (fMethodVariables != null) {
1070                                 VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_GLOBAL_VAR);
1071                                 fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1072                         }
1073                         addVariableSet(set);
1074                         getNextToken();
1075                 } else if (token == TokenNameDOLLAR) {
1076                         getNextToken();
1077                         if (token == TokenNameLBRACE) {
1078                                 getNextToken();
1079                                 expr();
1080                                 if (token != TokenNameRBRACE) {
1081                                         throwSyntaxError("'}' expected in global variable.");
1082                                 }
1083                                 getNextToken();
1084                         } else {
1085                                 r_variable();
1086                         }
1087                 }
1088         }
1089
1090         private void static_var_list() {
1091                 // static_var_list:
1092                 // static_var_list ',' T_VARIABLE
1093                 // | static_var_list ',' T_VARIABLE '=' static_scalar
1094                 // | T_VARIABLE
1095                 // | T_VARIABLE '=' static_scalar,
1096                 HashSet set = peekVariableSet();
1097                 while (true) {
1098                         if (token == TokenNameVariable) {
1099                                 if (fMethodVariables != null) {
1100                                         VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_STATIC_VAR);
1101                                         fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1102                                 }
1103                                 addVariableSet(set);
1104                                 getNextToken();
1105                                 if (token == TokenNameEQUAL) {
1106                                         getNextToken();
1107                                         static_scalar();
1108                                 }
1109                                 if (token != TokenNameCOMMA) {
1110                                         break;
1111                                 }
1112                                 getNextToken();
1113                         } else {
1114                                 break;
1115                         }
1116                 }
1117         }
1118
1119         private void unset_variables() {
1120                 // unset_variables:
1121                 // unset_variable
1122                 // | unset_variables ',' unset_variable
1123                 // unset_variable:
1124                 // variable
1125                 while (true) {
1126                         variable(false, false);
1127                         if (token != TokenNameCOMMA) {
1128                                 break;
1129                         }
1130                         getNextToken();
1131                 }
1132         }
1133
1134         private final void initializeModifiers() {
1135                 this.modifiers = 0;
1136                 this.modifiersSourceStart = -1;
1137         }
1138
1139         private final void checkAndSetModifiers(int flag) {
1140                 this.modifiers |= flag;
1141                 if (this.modifiersSourceStart < 0)
1142                         this.modifiersSourceStart = this.scanner.startPosition;
1143         }
1144
1145         private void unticked_class_declaration_statement(TypeDeclaration typeDecl) {
1146                 initializeModifiers();
1147                 if (token == TokenNameinterface) {
1148                         // interface_entry T_STRING
1149                         // interface_extends_list
1150                         // '{' class_statement_list '}'
1151                         checkAndSetModifiers(AccInterface);
1152                         getNextToken();
1153                         typeDecl.modifiers = this.modifiers;
1154                         typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1155                         typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1156                         if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
1157                                 typeDecl.name = scanner.getCurrentIdentifierSource();
1158                                 if (token > TokenNameKEYWORD) {
1159                                         problemReporter.phpKeywordWarning(new String[] { scanner.toStringAction(token) }, scanner.getCurrentTokenStartPosition(),
1160                                                         scanner.getCurrentTokenEndPosition(), referenceContext, compilationUnit.compilationResult);
1161                                         // throwSyntaxError("Don't use a keyword for interface declaration ["
1162                                         // + scanner.toStringAction(token) + "].",
1163                                         // typeDecl.sourceStart, typeDecl.sourceEnd);
1164                                 }
1165                                 getNextToken();
1166                                 interface_extends_list(typeDecl);
1167                         } else {
1168                                 typeDecl.name = new char[] { ' ' };
1169                                 throwSyntaxError("Interface name expected after keyword 'interface'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1170                                 return;
1171                         }
1172                 } else {
1173                         // class_entry_type T_STRING extends_from
1174                         // implements_list
1175                         // '{' class_statement_list'}'
1176                         class_entry_type();
1177                         typeDecl.modifiers = this.modifiers;
1178                         typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1179                         typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1180                         // identifier
1181                         // identifier 'extends' identifier
1182                         if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
1183                                 typeDecl.name = scanner.getCurrentIdentifierSource();
1184                                 if (token > TokenNameKEYWORD) {
1185                                         problemReporter.phpKeywordWarning(new String[] { scanner.toStringAction(token) }, scanner.getCurrentTokenStartPosition(),
1186                                                         scanner.getCurrentTokenEndPosition(), referenceContext, compilationUnit.compilationResult);
1187                                         // throwSyntaxError("Don't use a keyword for class declaration [" +
1188                                         // scanner.toStringAction(token) + "].",
1189                                         // typeDecl.sourceStart, typeDecl.sourceEnd);
1190                                 }
1191                                 getNextToken();
1192                                 // extends_from:
1193                                 // /* empty */
1194                                 // | T_EXTENDS fully_qualified_class_name
1195                                 if (token == TokenNameextends) {
1196                                         class_extends_list(typeDecl);
1197                                         // getNextToken();
1198                                         // if (token != TokenNameIdentifier) {
1199                                         // throwSyntaxError("Class name expected after keyword
1200                                         // 'extends'.",
1201                                         // scanner.getCurrentTokenStartPosition(), scanner
1202                                         // .getCurrentTokenEndPosition());
1203                                         // }
1204                                 }
1205                                 implements_list(typeDecl);
1206                         } else {
1207                                 typeDecl.name = new char[] { ' ' };
1208                                 throwSyntaxError("Class name expected after keyword 'class'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1209                                 return;
1210                         }
1211                 }
1212                 // '{' class_statement_list '}'
1213                 if (token == TokenNameLBRACE) {
1214                         getNextToken();
1215                         if (token != TokenNameRBRACE) {
1216                                 ArrayList list = new ArrayList();
1217                                 class_statement_list(list);
1218                                 typeDecl.fields = new FieldDeclaration[list.size()];
1219                                 for (int i = 0; i < list.size(); i++) {
1220                                         typeDecl.fields[i] = (FieldDeclaration) list.get(i);
1221                                 }
1222                         }
1223                         if (token == TokenNameRBRACE) {
1224                                 typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1225                                 getNextToken();
1226                         } else {
1227                                 throwSyntaxError("'}' expected at end of class body.");
1228                         }
1229                 } else {
1230                         throwSyntaxError("'{' expected at start of class body.");
1231                 }
1232         }
1233
1234         private void class_entry_type() {
1235                 // T_CLASS
1236                 // | T_ABSTRACT T_CLASS
1237                 // | T_FINAL T_CLASS
1238                 if (token == TokenNameclass) {
1239                         getNextToken();
1240                 } else if (token == TokenNameabstract) {
1241                         checkAndSetModifiers(AccAbstract);
1242                         getNextToken();
1243                         if (token != TokenNameclass) {
1244                                 throwSyntaxError("Keyword 'class' expected after keyword 'abstract'.");
1245                         }
1246                         getNextToken();
1247                 } else if (token == TokenNamefinal) {
1248                         checkAndSetModifiers(AccFinal);
1249                         getNextToken();
1250                         if (token != TokenNameclass) {
1251                                 throwSyntaxError("Keyword 'class' expected after keyword 'final'.");
1252                         }
1253                         getNextToken();
1254                 } else {
1255                         throwSyntaxError("Keyword 'class' 'final' or 'abstract' expected");
1256                 }
1257         }
1258
1259         // private void class_extends(TypeDeclaration typeDecl) {
1260         // // /* empty */
1261         // // | T_EXTENDS interface_list
1262         // if (token == TokenNameextends) {
1263         // getNextToken();
1264         //
1265         // if (token == TokenNameIdentifier) {
1266         // getNextToken();
1267         // } else {
1268         // throwSyntaxError("Class name expected after keyword 'extends'.");
1269         // }
1270         // }
1271         // }
1272
1273         private void interface_extends_list(TypeDeclaration typeDecl) {
1274                 // /* empty */
1275                 // | T_EXTENDS interface_list
1276                 if (token == TokenNameextends) {
1277                         getNextToken();
1278                         interface_list(typeDecl);
1279                 }
1280         }
1281
1282         private void class_extends_list(TypeDeclaration typeDecl) {
1283                 // /* empty */
1284                 // | T_EXTENDS interface_list
1285                 if (token == TokenNameextends) {
1286                         getNextToken();
1287                         class_list(typeDecl);
1288                 }
1289         }
1290
1291         private void implements_list(TypeDeclaration typeDecl) {
1292                 // /* empty */
1293                 // | T_IMPLEMENTS interface_list
1294                 if (token == TokenNameimplements) {
1295                         getNextToken();
1296                         interface_list(typeDecl);
1297                 }
1298         }
1299
1300         private void class_list(TypeDeclaration typeDecl) {
1301                 // class_list:
1302                 // fully_qualified_class_name
1303                 do {
1304                         if (token == TokenNameIdentifier) {
1305                                 char[] ident = scanner.getCurrentIdentifierSource();
1306                                 // TODO make this code working better:
1307                                 // SingleTypeReference ref = ParserUtil.getTypeReference(scanner,
1308                                 // includesList, ident);
1309                                 // if (ref != null) {
1310                                 // typeDecl.superclass = ref;
1311                                 // }
1312                                 getNextToken();
1313                         } else {
1314                                 throwSyntaxError("Classname expected after keyword 'extends'.");
1315                         }
1316                         if (token == TokenNameCOMMA) {
1317                                 reportSyntaxError("No multiple inheritance allowed. Expected token 'implements' or '{'.");
1318                                 getNextToken();
1319                                 continue;
1320                         } else {
1321                                 break;
1322                         }
1323                 } while (true);
1324         }
1325
1326         private void interface_list(TypeDeclaration typeDecl) {
1327                 // interface_list:
1328                 // fully_qualified_class_name
1329                 // | interface_list ',' fully_qualified_class_name
1330                 do {
1331                         if (token == TokenNameIdentifier) {
1332                                 getNextToken();
1333                         } else {
1334                                 throwSyntaxError("Interfacename expected after keyword 'implements'.");
1335                         }
1336                         if (token != TokenNameCOMMA) {
1337                                 return;
1338                         }
1339                         getNextToken();
1340                 } while (true);
1341         }
1342
1343         // private void classBody(TypeDeclaration typeDecl) {
1344         // //'{' [class-element-list] '}'
1345         // if (token == TokenNameLBRACE) {
1346         // getNextToken();
1347         // if (token != TokenNameRBRACE) {
1348         // class_statement_list();
1349         // }
1350         // if (token == TokenNameRBRACE) {
1351         // typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1352         // getNextToken();
1353         // } else {
1354         // throwSyntaxError("'}' expected at end of class body.");
1355         // }
1356         // } else {
1357         // throwSyntaxError("'{' expected at start of class body.");
1358         // }
1359         // }
1360         private void class_statement_list(ArrayList list) {
1361                 do {
1362                         try {
1363                                 class_statement(list);
1364                                 if (token == TokenNamepublic || token == TokenNameprotected || token == TokenNameprivate || token == TokenNamestatic
1365                                                 || token == TokenNameabstract || token == TokenNamefinal || token == TokenNamefunction || token == TokenNamevar
1366                                                 || token == TokenNameconst) {
1367                                         continue;
1368                                 }
1369                                 if (token == TokenNameRBRACE) {
1370                                         break;
1371                                 }
1372                                 throwSyntaxError("'}' at end of class statement.");
1373                         } catch (SyntaxError sytaxErr1) {
1374                                 boolean tokenize = scanner.tokenizeStrings;
1375                                 if (!tokenize) {
1376                                         scanner.tokenizeStrings = true;
1377                                 }
1378                                 try {
1379                                         // if an error occured,
1380                                         // try to find keywords
1381                                         // to parse the rest of the string
1382                                         while (token != TokenNameEOF) {
1383                                                 if (token == TokenNamepublic || token == TokenNameprotected || token == TokenNameprivate || token == TokenNamestatic
1384                                                                 || token == TokenNameabstract || token == TokenNamefinal || token == TokenNamefunction || token == TokenNamevar
1385                                                                 || token == TokenNameconst) {
1386                                                         break;
1387                                                 }
1388                                                 // System.out.println(scanner.toStringAction(token));
1389                                                 getNextToken();
1390                                         }
1391                                         if (token == TokenNameEOF) {
1392                                                 throw sytaxErr1;
1393                                         }
1394                                 } finally {
1395                                         scanner.tokenizeStrings = tokenize;
1396                                 }
1397                         }
1398                 } while (true);
1399         }
1400
1401         private void class_statement(ArrayList list) {
1402                 // class_statement:
1403                 // variable_modifiers class_variable_declaration ';'
1404                 // | class_constant_declaration ';'
1405                 // | method_modifiers T_FUNCTION is_reference T_STRING
1406                 // '(' parameter_list ')' method_body
1407                 initializeModifiers();
1408                 int declarationSourceStart = scanner.getCurrentTokenStartPosition();
1409
1410                 if (token == TokenNamevar) {
1411                         checkAndSetModifiers(AccPublic);
1412                         problemReporter.phpVarDeprecatedWarning(scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(),
1413                                         referenceContext, compilationUnit.compilationResult);
1414                         getNextToken();
1415                         class_variable_declaration(declarationSourceStart, list);
1416                 } else if (token == TokenNameconst) {
1417                         checkAndSetModifiers(AccFinal | AccPublic);
1418                         class_constant_declaration(declarationSourceStart, list);
1419                         if (token != TokenNameSEMICOLON) {
1420                                 throwSyntaxError("';' expected after class const declaration.");
1421                         }
1422                         getNextToken();
1423                 } else {
1424                         boolean hasModifiers = member_modifiers();
1425                         if (token == TokenNamefunction) {
1426                                 if (!hasModifiers) {
1427                                         checkAndSetModifiers(AccPublic);
1428                                 }
1429                                 MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1430                                 methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1431                                 methodDecl.modifiers = this.modifiers;
1432                                 methodDecl.type = MethodDeclaration.METHOD_DEFINITION;
1433                                 try {
1434                                         getNextToken();
1435                                         functionDefinition(methodDecl);
1436                                 } finally {
1437                                         int sourceEnd = methodDecl.sourceEnd;
1438                                         if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) {
1439                                                 sourceEnd = methodDecl.declarationSourceStart + 1;
1440                                         }
1441                                         methodDecl.declarationSourceEnd = sourceEnd;
1442                                         methodDecl.sourceEnd = sourceEnd;
1443                                 }
1444                         } else {
1445                                 if (!hasModifiers) {
1446                                         throwSyntaxError("'public' 'private' or 'protected' modifier expected for field declarations.");
1447                                 }
1448                                 class_variable_declaration(declarationSourceStart, list);
1449                         }
1450                 }
1451         }
1452
1453         private void class_constant_declaration(int declarationSourceStart, ArrayList list) {
1454                 // class_constant_declaration ',' T_STRING '=' static_scalar
1455                 // | T_CONST T_STRING '=' static_scalar
1456                 if (token != TokenNameconst) {
1457                         throwSyntaxError("'const' keyword expected in class declaration.");
1458                 } else {
1459                         getNextToken();
1460                 }
1461                 while (true) {
1462                         if (token != TokenNameIdentifier) {
1463                                 throwSyntaxError("Identifier expected in class const declaration.");
1464                         }
1465                         FieldDeclaration fieldDeclaration = new FieldDeclaration(scanner.getCurrentIdentifierSource(), scanner
1466                                         .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
1467                         fieldDeclaration.modifiers = this.modifiers;
1468                         fieldDeclaration.declarationSourceStart = declarationSourceStart;
1469                         fieldDeclaration.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1470                         fieldDeclaration.modifiersSourceStart = declarationSourceStart;
1471                         // fieldDeclaration.type
1472                         list.add(fieldDeclaration);
1473                         getNextToken();
1474                         if (token != TokenNameEQUAL) {
1475                                 throwSyntaxError("'=' expected in class const declaration.");
1476                         }
1477                         getNextToken();
1478                         static_scalar();
1479                         if (token != TokenNameCOMMA) {
1480                                 break; // while(true)-loop
1481                         }
1482                         getNextToken();
1483                 }
1484         }
1485
1486         // private void variable_modifiers() {
1487         // // variable_modifiers:
1488         // // non_empty_member_modifiers
1489         // //| T_VAR
1490         // initializeModifiers();
1491         // if (token == TokenNamevar) {
1492         // checkAndSetModifiers(AccPublic);
1493         // reportSyntaxError(
1494         // "Keyword 'var' is deprecated. Please use 'public' 'private' or
1495         // 'protected'
1496         // modifier for field declarations.",
1497         // scanner.getCurrentTokenStartPosition(), scanner
1498         // .getCurrentTokenEndPosition());
1499         // getNextToken();
1500         // } else {
1501         // if (!member_modifiers()) {
1502         // throwSyntaxError("'public' 'private' or 'protected' modifier expected for
1503         // field declarations.");
1504         // }
1505         // }
1506         // }
1507         // private void method_modifiers() {
1508         // //method_modifiers:
1509         // // /* empty */
1510         // //| non_empty_member_modifiers
1511         // initializeModifiers();
1512         // if (!member_modifiers()) {
1513         // checkAndSetModifiers(AccPublic);
1514         // }
1515         // }
1516         private boolean member_modifiers() {
1517                 // T_PUBLIC
1518                 // | T_PROTECTED
1519                 // | T_PRIVATE
1520                 // | T_STATIC
1521                 // | T_ABSTRACT
1522                 // | T_FINAL
1523                 boolean foundToken = false;
1524                 while (true) {
1525                         if (token == TokenNamepublic) {
1526                                 checkAndSetModifiers(AccPublic);
1527                                 getNextToken();
1528                                 foundToken = true;
1529                         } else if (token == TokenNameprotected) {
1530                                 checkAndSetModifiers(AccProtected);
1531                                 getNextToken();
1532                                 foundToken = true;
1533                         } else if (token == TokenNameprivate) {
1534                                 checkAndSetModifiers(AccPrivate);
1535                                 getNextToken();
1536                                 foundToken = true;
1537                         } else if (token == TokenNamestatic) {
1538                                 checkAndSetModifiers(AccStatic);
1539                                 getNextToken();
1540                                 foundToken = true;
1541                         } else if (token == TokenNameabstract) {
1542                                 checkAndSetModifiers(AccAbstract);
1543                                 getNextToken();
1544                                 foundToken = true;
1545                         } else if (token == TokenNamefinal) {
1546                                 checkAndSetModifiers(AccFinal);
1547                                 getNextToken();
1548                                 foundToken = true;
1549                         } else {
1550                                 break;
1551                         }
1552                 }
1553                 return foundToken;
1554         }
1555
1556         private void class_variable_declaration(int declarationSourceStart, ArrayList list) {
1557                 // class_variable_declaration:
1558                 // class_variable_declaration ',' T_VARIABLE
1559                 // | class_variable_declaration ',' T_VARIABLE '=' static_scalar
1560                 // | T_VARIABLE
1561                 // | T_VARIABLE '=' static_scalar
1562                 char[] classVariable;
1563                 do {
1564                         if (token == TokenNameVariable) {
1565                                 classVariable = scanner.getCurrentIdentifierSource();
1566                                 // indexManager.addIdentifierInformation('v', classVariable, buf, -1,
1567                                 // -1);
1568                                 FieldDeclaration fieldDeclaration = new FieldDeclaration(classVariable, scanner.getCurrentTokenStartPosition(), scanner
1569                                                 .getCurrentTokenEndPosition());
1570                                 fieldDeclaration.modifiers = this.modifiers;
1571                                 fieldDeclaration.declarationSourceStart = declarationSourceStart;
1572                                 fieldDeclaration.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1573                                 fieldDeclaration.modifiersSourceStart = declarationSourceStart;
1574                                 list.add(fieldDeclaration);
1575                                 if (fTypeVariables != null) {
1576                                         VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_CLASS_UNIT);
1577                                         fTypeVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1578                                 }
1579                                 getNextToken();
1580                                 if (token == TokenNameEQUAL) {
1581                                         getNextToken();
1582                                         static_scalar();
1583                                 }
1584                         } else {
1585                                 // if (token == TokenNamethis) {
1586                                 // throwSyntaxError("'$this' not allowed after keyword 'public'
1587                                 // 'protected' 'private' 'var'.");
1588                                 // }
1589                                 throwSyntaxError("Variable expected after keyword 'public' 'protected' 'private' 'var'.");
1590                         }
1591                         if (token != TokenNameCOMMA) {
1592                                 break;
1593                         }
1594                         getNextToken();
1595                 } while (true);
1596                 if (token != TokenNameSEMICOLON) {
1597                         throwSyntaxError("';' expected after field declaration.");
1598                 }
1599                 getNextToken();
1600         }
1601
1602         private void functionDefinition(MethodDeclaration methodDecl) {
1603                 boolean isAbstract = false;
1604                 if (astPtr == 0) {
1605                         if (compilationUnit != null) {
1606                                 compilationUnit.types.add(methodDecl);
1607                         }
1608                 } else {
1609                         ASTNode node = astStack[astPtr];
1610                         if (node instanceof TypeDeclaration) {
1611                                 TypeDeclaration typeDecl = ((TypeDeclaration) node);
1612                                 if (typeDecl.methods == null) {
1613                                         typeDecl.methods = new AbstractMethodDeclaration[] { methodDecl };
1614                                 } else {
1615                                         AbstractMethodDeclaration[] newMethods;
1616                                         System.arraycopy(typeDecl.methods, 0, newMethods = new AbstractMethodDeclaration[typeDecl.methods.length + 1], 0,
1617                                                         typeDecl.methods.length);
1618                                         newMethods[typeDecl.methods.length] = methodDecl;
1619                                         typeDecl.methods = newMethods;
1620                                 }
1621                                 if ((typeDecl.modifiers & AccAbstract) == AccAbstract) {
1622                                         isAbstract = true;
1623                                 } else if ((typeDecl.modifiers & AccInterface) == AccInterface) {
1624                                         isAbstract = true;
1625                                 }
1626                         }
1627                 }
1628                 try {
1629                         pushFunctionVariableSet();
1630                         functionDeclarator(methodDecl);
1631                         if (token == TokenNameSEMICOLON) {
1632                                 if (!isAbstract) {
1633                                         methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1;
1634                                         throwSyntaxError("Body declaration expected for method: " + new String(methodDecl.selector));
1635                                 }
1636                                 getNextToken();
1637                                 return;
1638                         }
1639                         functionBody(methodDecl);
1640                 } finally {
1641                         if (!fStackUnassigned.isEmpty()) {
1642                                 fStackUnassigned.remove(fStackUnassigned.size() - 1);
1643                         }
1644                 }
1645         }
1646
1647         private void functionDeclarator(MethodDeclaration methodDecl) {
1648                 // identifier '(' [parameter-list] ')'
1649                 if (token == TokenNameAND) {
1650                         getNextToken();
1651                 }
1652                 methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1653                 methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1654                 if (Scanner.isIdentifierOrKeyword(token)) {
1655                         methodDecl.selector = scanner.getCurrentIdentifierSource();
1656                         if (token > TokenNameKEYWORD) {
1657                                 problemReporter.phpKeywordWarning(new String[] { scanner.toStringAction(token) }, scanner.getCurrentTokenStartPosition(),
1658                                                 scanner.getCurrentTokenEndPosition(), referenceContext, compilationUnit.compilationResult);
1659                         }
1660                         getNextToken();
1661                         if (token == TokenNameLPAREN) {
1662                                 getNextToken();
1663                         } else {
1664                                 methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1;
1665                                 throwSyntaxError("'(' expected in function declaration.");
1666                         }
1667                         if (token != TokenNameRPAREN) {
1668                                 parameter_list(methodDecl);
1669                         }
1670                         if (token != TokenNameRPAREN) {
1671                                 methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1;
1672                                 throwSyntaxError("')' expected in function declaration.");
1673                         } else {
1674                                 methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1;
1675                                 getNextToken();
1676                         }
1677                 } else {
1678                         methodDecl.selector = "<undefined>".toCharArray();
1679                         methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1;
1680                         throwSyntaxError("Function name expected after keyword 'function'.");
1681                 }
1682         }
1683
1684         //
1685         private void parameter_list(MethodDeclaration methodDecl) {
1686                 // non_empty_parameter_list
1687                 // | /* empty */
1688                 non_empty_parameter_list(methodDecl, true);
1689         }
1690
1691         private void non_empty_parameter_list(MethodDeclaration methodDecl, boolean empty_allowed) {
1692                 // optional_class_type T_VARIABLE
1693                 // | optional_class_type '&' T_VARIABLE
1694                 // | optional_class_type '&' T_VARIABLE '=' static_scalar
1695                 // | optional_class_type T_VARIABLE '=' static_scalar
1696                 // | non_empty_parameter_list ',' optional_class_type T_VARIABLE
1697                 // | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE
1698                 // | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '='
1699                 // static_scalar
1700                 // | non_empty_parameter_list ',' optional_class_type T_VARIABLE '='
1701                 // static_scalar
1702                 char[] typeIdentifier = null;
1703                 if (token == TokenNameIdentifier || token == TokenNamearray || token == TokenNameVariable || token == TokenNameAND) {
1704                         HashSet set = peekVariableSet();
1705                         while (true) {
1706                                 if (token == TokenNameIdentifier || token == TokenNamearray) {// feature req. #1254275
1707                                         typeIdentifier = scanner.getCurrentIdentifierSource();
1708                                         getNextToken();
1709                                 }
1710                                 if (token == TokenNameAND) {
1711                                         getNextToken();
1712                                 }
1713                                 if (token == TokenNameVariable) {
1714                                         if (fMethodVariables != null) {
1715                                                 VariableInfo info;
1716                                                 if (methodDecl.type == MethodDeclaration.FUNCTION_DEFINITION) {
1717                                                         info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_FUNCTION_DEFINITION);
1718                                                 } else {
1719                                                         info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_METHOD_DEFINITION);
1720                                                 }
1721                                                 info.typeIdentifier = typeIdentifier;
1722                                                 fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info);
1723                                         }
1724                                         addVariableSet(set);
1725                                         getNextToken();
1726                                         if (token == TokenNameEQUAL) {
1727                                                 getNextToken();
1728                                                 static_scalar();
1729                                         }
1730                                 } else {
1731                                         throwSyntaxError("Variable expected in parameter list.");
1732                                 }
1733                                 if (token != TokenNameCOMMA) {
1734                                         break;
1735                                 }
1736                                 getNextToken();
1737                         }
1738                         return;
1739                 }
1740                 if (!empty_allowed) {
1741                         throwSyntaxError("Identifier expected in parameter list.");
1742                 }
1743         }
1744
1745         private void optional_class_type() {
1746                 // /* empty */
1747                 // | T_STRING
1748         }
1749
1750         // private void parameterDeclaration() {
1751         // //variable
1752         // //variable-reference
1753         // if (token == TokenNameAND) {
1754         // getNextToken();
1755         // if (isVariable()) {
1756         // getNextToken();
1757         // } else {
1758         // throwSyntaxError("Variable expected after reference operator '&'.");
1759         // }
1760         // }
1761         // //variable '=' constant
1762         // if (token == TokenNameVariable) {
1763         // getNextToken();
1764         // if (token == TokenNameEQUAL) {
1765         // getNextToken();
1766         // static_scalar();
1767         // }
1768         // return;
1769         // }
1770         // // if (token == TokenNamethis) {
1771         // // throwSyntaxError("Reserved word '$this' not allowed in parameter
1772         // // declaration.");
1773         // // }
1774         // }
1775
1776         private void labeledStatementList() {
1777                 if (token != TokenNamecase && token != TokenNamedefault) {
1778                         throwSyntaxError("'case' or 'default' expected.");
1779                 }
1780                 do {
1781                         if (token == TokenNamecase) {
1782                                 getNextToken();
1783                                 expr(); // constant();
1784                                 if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
1785                                         getNextToken();
1786                                         if (token == TokenNameRBRACE) {
1787                                                 // empty case; assumes that the '}' token belongs to the wrapping
1788                                                 // switch statement - #1371992
1789                                                 break;
1790                                         }
1791                                         if (token == TokenNamecase || token == TokenNamedefault) {
1792                                                 // empty case statement ?
1793                                                 continue;
1794                                         }
1795                                         statementList();
1796                                 }
1797                                 // else if (token == TokenNameSEMICOLON) {
1798                                 // setMarker(
1799                                 // "':' expected after 'case' keyword (Found token: " +
1800                                 // scanner.toStringAction(token) + ")",
1801                                 // scanner.getCurrentTokenStartPosition(),
1802                                 // scanner.getCurrentTokenEndPosition(),
1803                                 // INFO);
1804                                 // getNextToken();
1805                                 // if (token == TokenNamecase) { // empty case statement ?
1806                                 // continue;
1807                                 // }
1808                                 // statementList();
1809                                 // }
1810                                 else {
1811                                         throwSyntaxError("':' character expected after 'case' constant (Found token: " + scanner.toStringAction(token) + ")");
1812                                 }
1813                         } else { // TokenNamedefault
1814                                 getNextToken();
1815                                 if (token == TokenNameCOLON || token == TokenNameSEMICOLON) {
1816                                         getNextToken();
1817                                         if (token == TokenNameRBRACE) {
1818                                                 // empty default case; ; assumes that the '}' token belongs to the
1819                                                 // wrapping switch statement - #1371992
1820                                                 break;
1821                                         }
1822                                         if (token != TokenNamecase) {
1823                                                 statementList();
1824                                         }
1825                                 } else {
1826                                         throwSyntaxError("':' character expected after 'default'.");
1827                                 }
1828                         }
1829                 } while (token == TokenNamecase || token == TokenNamedefault);
1830         }
1831
1832         private void ifStatementColon(IfStatement iState) {
1833                 // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list
1834                 // new_else_single T_ENDIF ';'
1835                 HashSet assignedVariableSet = null;
1836                 try {
1837                         Block b = inner_statement_list();
1838                         iState.thenStatement = b;
1839                         checkUnreachable(iState, b);
1840                 } finally {
1841                         assignedVariableSet = removeIfVariableSet();
1842                 }
1843                 if (token == TokenNameelseif) {
1844                         try {
1845                                 pushIfVariableSet();
1846                                 new_elseif_list(iState);
1847                         } finally {
1848                                 HashSet set = removeIfVariableSet();
1849                                 if (assignedVariableSet != null && set != null) {
1850                                         assignedVariableSet.addAll(set);
1851                                 }
1852                         }
1853                 }
1854                 try {
1855                         pushIfVariableSet();
1856                         new_else_single(iState);
1857                 } finally {
1858                         HashSet set = removeIfVariableSet();
1859                         if (assignedVariableSet != null) {
1860                                 HashSet topSet = peekVariableSet();
1861                                 if (topSet != null) {
1862                                         if (set != null) {
1863                                                 topSet.addAll(set);
1864                                         }
1865                                         topSet.addAll(assignedVariableSet);
1866                                 }
1867                         }
1868                 }
1869                 if (token != TokenNameendif) {
1870                         throwSyntaxError("'endif' expected.");
1871                 }
1872                 getNextToken();
1873                 if (token != TokenNameSEMICOLON) {
1874                         reportSyntaxError("';' expected after if-statement.");
1875                         iState.sourceEnd = scanner.getCurrentTokenStartPosition();
1876                 } else {
1877                         iState.sourceEnd = scanner.getCurrentTokenEndPosition();
1878                         getNextToken();
1879                 }
1880         }
1881
1882         private void ifStatement(IfStatement iState) {
1883                 // T_IF '(' expr ')' statement elseif_list else_single
1884                 HashSet assignedVariableSet = null;
1885                 try {
1886                         pushIfVariableSet();
1887                         Statement s = statement();
1888                         iState.thenStatement = s;
1889                         checkUnreachable(iState, s);
1890                 } finally {
1891                         assignedVariableSet = removeIfVariableSet();
1892                 }
1893
1894                 if (token == TokenNameelseif) {
1895                         try {
1896                                 pushIfVariableSet();
1897                                 elseif_list(iState);
1898                         } finally {
1899                                 HashSet set = removeIfVariableSet();
1900                                 if (assignedVariableSet != null && set != null) {
1901                                         assignedVariableSet.addAll(set);
1902                                 }
1903                         }
1904                 }
1905                 try {
1906                         pushIfVariableSet();
1907                         else_single(iState);
1908                 } finally {
1909                         HashSet set = removeIfVariableSet();
1910                         if (assignedVariableSet != null) {
1911                                 HashSet topSet = peekVariableSet();
1912                                 if (topSet != null) {
1913                                         if (set != null) {
1914                                                 topSet.addAll(set);
1915                                         }
1916                                         topSet.addAll(assignedVariableSet);
1917                                 }
1918                         }
1919                 }
1920         }
1921
1922         private void elseif_list(IfStatement iState) {
1923                 // /* empty */
1924                 // | elseif_list T_ELSEIF '(' expr ')' statement
1925                 ArrayList conditionList = new ArrayList();
1926                 ArrayList statementList = new ArrayList();
1927                 Expression e;
1928                 Statement s;
1929                 while (token == TokenNameelseif) {
1930                         getNextToken();
1931                         if (token == TokenNameLPAREN) {
1932                                 getNextToken();
1933                         } else {
1934                                 throwSyntaxError("'(' expected after 'elseif' keyword.");
1935                         }
1936                         e = expr();
1937                         conditionList.add(e);
1938                         if (token == TokenNameRPAREN) {
1939                                 getNextToken();
1940                         } else {
1941                                 throwSyntaxError("')' expected after 'elseif' condition.");
1942                         }
1943                         s = statement();
1944                         statementList.add(s);
1945                         checkUnreachable(iState, s);
1946                 }
1947                 iState.elseifConditions = new Expression[conditionList.size()];
1948                 iState.elseifStatements = new Statement[statementList.size()];
1949                 conditionList.toArray(iState.elseifConditions);
1950                 statementList.toArray(iState.elseifStatements);
1951         }
1952
1953         private void new_elseif_list(IfStatement iState) {
1954                 // /* empty */
1955                 // | new_elseif_list T_ELSEIF '(' expr ')' ':' inner_statement_list
1956                 ArrayList conditionList = new ArrayList();
1957                 ArrayList statementList = new ArrayList();
1958                 Expression e;
1959                 Block b;
1960                 while (token == TokenNameelseif) {
1961                         getNextToken();
1962                         if (token == TokenNameLPAREN) {
1963                                 getNextToken();
1964                         } else {
1965                                 throwSyntaxError("'(' expected after 'elseif' keyword.");
1966                         }
1967                         e = expr();
1968                         conditionList.add(e);
1969                         if (token == TokenNameRPAREN) {
1970                                 getNextToken();
1971                         } else {
1972                                 throwSyntaxError("')' expected after 'elseif' condition.");
1973                         }
1974                         if (token == TokenNameCOLON) {
1975                                 getNextToken();
1976                         } else {
1977                                 throwSyntaxError("':' expected after 'elseif' keyword.");
1978                         }
1979                         b = inner_statement_list();
1980                         statementList.add(b);
1981                         checkUnreachable(iState, b);
1982                 }
1983                 iState.elseifConditions = new Expression[conditionList.size()];
1984                 iState.elseifStatements = new Statement[statementList.size()];
1985                 conditionList.toArray(iState.elseifConditions);
1986                 statementList.toArray(iState.elseifStatements);
1987         }
1988
1989         private void else_single(IfStatement iState) {
1990                 // /* empty */
1991                 // T_ELSE statement
1992                 if (token == TokenNameelse) {
1993                         getNextToken();
1994                         Statement s = statement();
1995                         iState.elseStatement = s;
1996                         checkUnreachable(iState, s);
1997                 } else {
1998                         iState.checkUnreachable = false;
1999                 }
2000                 iState.sourceEnd = scanner.getCurrentTokenStartPosition();
2001         }
2002
2003         private void new_else_single(IfStatement iState) {
2004                 // /* empty */
2005                 // | T_ELSE ':' inner_statement_list
2006                 if (token == TokenNameelse) {
2007                         getNextToken();
2008                         if (token == TokenNameCOLON) {
2009                                 getNextToken();
2010                         } else {
2011                                 throwSyntaxError("':' expected after 'else' keyword.");
2012                         }
2013                         Block b = inner_statement_list();
2014                         iState.elseStatement = b;
2015                         checkUnreachable(iState, b);
2016                 } else {
2017                         iState.checkUnreachable = false;
2018                 }
2019         }
2020
2021         private Block inner_statement_list() {
2022                 // inner_statement_list inner_statement
2023                 // /* empty */
2024                 return statementList();
2025         }
2026
2027         /**
2028          * @param iState
2029          * @param b
2030          */
2031         private void checkUnreachable(IfStatement iState, Statement s) {
2032                 if (s instanceof Block) {
2033                         Block b = (Block) s;
2034                         if (b.statements == null || b.statements.length == 0) {
2035                                 iState.checkUnreachable = false;
2036                         } else {
2037                                 int off = b.statements.length - 1;
2038                                 if (!(b.statements[off] instanceof ReturnStatement) && !(b.statements[off] instanceof ContinueStatement)
2039                                                 && !(b.statements[off] instanceof BreakStatement)) {
2040                                         if (!(b.statements[off] instanceof IfStatement) || !((IfStatement) b.statements[off]).checkUnreachable) {
2041                                                 iState.checkUnreachable = false;
2042                                         }
2043                                 }
2044                         }
2045                 } else {
2046                         if (!(s instanceof ReturnStatement) && !(s instanceof ContinueStatement) && !(s instanceof BreakStatement)) {
2047                                 if (!(s instanceof IfStatement) || !((IfStatement) s).checkUnreachable) {
2048                                         iState.checkUnreachable = false;
2049                                 }
2050                         }
2051                 }
2052         }
2053
2054         // private void elseifStatementList() {
2055         // do {
2056         // elseifStatement();
2057         // switch (token) {
2058         // case TokenNameelse:
2059         // getNextToken();
2060         // if (token == TokenNameCOLON) {
2061         // getNextToken();
2062         // if (token != TokenNameendif) {
2063         // statementList();
2064         // }
2065         // return;
2066         // } else {
2067         // if (token == TokenNameif) { //'else if'
2068         // getNextToken();
2069         // } else {
2070         // throwSyntaxError("':' expected after 'else'.");
2071         // }
2072         // }
2073         // break;
2074         // case TokenNameelseif:
2075         // getNextToken();
2076         // break;
2077         // default:
2078         // return;
2079         // }
2080         // } while (true);
2081         // }
2082
2083         // private void elseifStatement() {
2084         // if (token == TokenNameLPAREN) {
2085         // getNextToken();
2086         // expr();
2087         // if (token != TokenNameRPAREN) {
2088         // throwSyntaxError("')' expected in else-if-statement.");
2089         // }
2090         // getNextToken();
2091         // if (token != TokenNameCOLON) {
2092         // throwSyntaxError("':' expected in else-if-statement.");
2093         // }
2094         // getNextToken();
2095         // if (token != TokenNameendif) {
2096         // statementList();
2097         // }
2098         // }
2099         // }
2100
2101         private void switchStatement() {
2102                 if (token == TokenNameCOLON) {
2103                         // ':' [labeled-statement-list] 'endswitch' ';'
2104                         getNextToken();
2105                         labeledStatementList();
2106                         if (token != TokenNameendswitch) {
2107                                 throwSyntaxError("'endswitch' expected.");
2108                         }
2109                         getNextToken();
2110                         if (token != TokenNameSEMICOLON) {
2111                                 throwSyntaxError("';' expected after switch-statement.");
2112                         }
2113                         getNextToken();
2114                 } else {
2115                         // '{' [labeled-statement-list] '}'
2116                         if (token != TokenNameLBRACE) {
2117                                 throwSyntaxError("'{' expected in switch statement.");
2118                         }
2119                         getNextToken();
2120                         if (token != TokenNameRBRACE) {
2121                                 labeledStatementList();
2122                         }
2123                         if (token != TokenNameRBRACE) {
2124                                 throwSyntaxError("'}' expected in switch statement.");
2125                         }
2126                         getNextToken();
2127                 }
2128         }
2129
2130         private void forStatement() {
2131                 if (token == TokenNameCOLON) {
2132                         getNextToken();
2133                         statementList();
2134                         if (token != TokenNameendfor) {
2135                                 throwSyntaxError("'endfor' expected.");
2136                         }
2137                         getNextToken();
2138                         if (token != TokenNameSEMICOLON) {
2139                                 throwSyntaxError("';' expected after for-statement.");
2140                         }
2141                         getNextToken();
2142                 } else {
2143                         statement();
2144                 }
2145         }
2146
2147         private void whileStatement() {
2148                 // ':' statement-list 'endwhile' ';'
2149                 if (token == TokenNameCOLON) {
2150                         getNextToken();
2151                         statementList();
2152                         if (token != TokenNameendwhile) {
2153                                 throwSyntaxError("'endwhile' expected.");
2154                         }
2155                         getNextToken();
2156                         if (token != TokenNameSEMICOLON) {
2157                                 throwSyntaxError("';' expected after while-statement.");
2158                         }
2159                         getNextToken();
2160                 } else {
2161                         statement();
2162                 }
2163         }
2164
2165         private void foreachStatement() {
2166                 if (token == TokenNameCOLON) {
2167                         getNextToken();
2168                         statementList();
2169                         if (token != TokenNameendforeach) {
2170                                 throwSyntaxError("'endforeach' expected.");
2171                         }
2172                         getNextToken();
2173                         if (token != TokenNameSEMICOLON) {
2174                                 throwSyntaxError("';' expected after foreach-statement.");
2175                         }
2176                         getNextToken();
2177                 } else {
2178                         statement();
2179                 }
2180         }
2181
2182         // private void exitStatus() {
2183         // if (token == TokenNameLPAREN) {
2184         // getNextToken();
2185         // } else {
2186         // throwSyntaxError("'(' expected in 'exit-status'.");
2187         // }
2188         // if (token != TokenNameRPAREN) {
2189         // expression();
2190         // }
2191         // if (token == TokenNameRPAREN) {
2192         // getNextToken();
2193         // } else {
2194         // throwSyntaxError("')' expected after 'exit-status'.");
2195         // }
2196         // }
2197         private void expressionList() {
2198                 do {
2199                         expr();
2200                         if (token == TokenNameCOMMA) {
2201                                 getNextToken();
2202                         } else {
2203                                 break;
2204                         }
2205                 } while (true);
2206         }
2207
2208         private Expression expr() {
2209                 // r_variable
2210                 // | expr_without_variable
2211                 // if (token!=TokenNameEOF) {
2212                 if (Scanner.TRACE) {
2213                         System.out.println("TRACE: expr()");
2214                 }
2215                 return expr_without_variable(true,null);
2216                 // }
2217         }
2218
2219         private Expression expr_without_variable(boolean only_variable, UninitializedVariableHandler initHandler) {
2220                 int exprSourceStart = scanner.getCurrentTokenStartPosition();
2221                 int exprSourceEnd = scanner.getCurrentTokenEndPosition();
2222                 Expression expression = new Expression();
2223                 expression.sourceStart = exprSourceStart;
2224                 // default, may be overwritten
2225                 expression.sourceEnd = exprSourceEnd;
2226                 try {
2227                         // internal_functions_in_yacc
2228                         // | T_CLONE expr
2229                         // | T_PRINT expr
2230                         // | '(' expr ')'
2231                         // | '@' expr
2232                         // | '+' expr
2233                         // | '-' expr
2234                         // | '!' expr
2235                         // | '~' expr
2236                         // | T_INC rw_variable
2237                         // | T_DEC rw_variable
2238                         // | T_INT_CAST expr
2239                         // | T_DOUBLE_CAST expr
2240                         // | T_STRING_CAST expr
2241                         // | T_ARRAY_CAST expr
2242                         // | T_OBJECT_CAST expr
2243                         // | T_BOOL_CAST expr
2244                         // | T_UNSET_CAST expr
2245                         // | T_EXIT exit_expr
2246                         // | scalar
2247                         // | T_ARRAY '(' array_pair_list ')'
2248                         // | '`' encaps_list '`'
2249                         // | T_LIST '(' assignment_list ')' '=' expr
2250                         // | T_NEW class_name_reference ctor_arguments
2251                         // | variable '=' expr
2252                         // | variable '=' '&' variable
2253                         // | variable '=' '&' T_NEW class_name_reference ctor_arguments
2254                         // | variable T_PLUS_EQUAL expr
2255                         // | variable T_MINUS_EQUAL expr
2256                         // | variable T_MUL_EQUAL expr
2257                         // | variable T_DIV_EQUAL expr
2258                         // | variable T_CONCAT_EQUAL expr
2259                         // | variable T_MOD_EQUAL expr
2260                         // | variable T_AND_EQUAL expr
2261                         // | variable T_OR_EQUAL expr
2262                         // | variable T_XOR_EQUAL expr
2263                         // | variable T_SL_EQUAL expr
2264                         // | variable T_SR_EQUAL expr
2265                         // | rw_variable T_INC
2266                         // | rw_variable T_DEC
2267                         // | expr T_BOOLEAN_OR expr
2268                         // | expr T_BOOLEAN_AND expr
2269                         // | expr T_LOGICAL_OR expr
2270                         // | expr T_LOGICAL_AND expr
2271                         // | expr T_LOGICAL_XOR expr
2272                         // | expr '|' expr
2273                         // | expr '&' expr
2274                         // | expr '^' expr
2275                         // | expr '.' expr
2276                         // | expr '+' expr
2277                         // | expr '-' expr
2278                         // | expr '*' expr
2279                         // | expr '/' expr
2280                         // | expr '%' expr
2281                         // | expr T_SL expr
2282                         // | expr T_SR expr
2283                         // | expr T_IS_IDENTICAL expr
2284                         // | expr T_IS_NOT_IDENTICAL expr
2285                         // | expr T_IS_EQUAL expr
2286                         // | expr T_IS_NOT_EQUAL expr
2287                         // | expr '<' expr
2288                         // | expr T_IS_SMALLER_OR_EQUAL expr
2289                         // | expr '>' expr
2290                         // | expr T_IS_GREATER_OR_EQUAL expr
2291                         // | expr T_INSTANCEOF class_name_reference
2292                         // | expr '?' expr ':' expr
2293                         if (Scanner.TRACE) {
2294                                 System.out.println("TRACE: expr_without_variable() PART 1");
2295                         }
2296                         switch (token) {
2297                         case TokenNameisset:
2298                                 // T_ISSET '(' isset_variables ')'
2299                                 getNextToken();
2300                                 if (token != TokenNameLPAREN) {
2301                                         throwSyntaxError("'(' expected after keyword 'isset'");
2302                                 }
2303                                 getNextToken();
2304                                 isset_variables();
2305                                 if (token != TokenNameRPAREN) {
2306                                         throwSyntaxError("')' expected after keyword 'isset'");
2307                                 }
2308                                 getNextToken();
2309                                 break;
2310                         case TokenNameempty:
2311                                 getNextToken();
2312                                 if (token != TokenNameLPAREN) {
2313                                         throwSyntaxError("'(' expected after keyword 'empty'");
2314                                 }
2315                                 getNextToken();
2316                                 variable(true, false);
2317                                 if (token != TokenNameRPAREN) {
2318                                         throwSyntaxError("')' expected after keyword 'empty'");
2319                                 }
2320                                 getNextToken();
2321                                 break;
2322                         case TokenNameeval:
2323                         case TokenNameinclude:
2324                         case TokenNameinclude_once:
2325                         case TokenNamerequire:
2326                         case TokenNamerequire_once:
2327                                 internal_functions_in_yacc();
2328                                 break;
2329                         // | '(' expr ')'
2330                         case TokenNameLPAREN:
2331                                 getNextToken();
2332                                 expr();
2333                                 if (token == TokenNameRPAREN) {
2334                                         getNextToken();
2335                                 } else {
2336                                         throwSyntaxError("')' expected in expression.");
2337                                 }
2338                                 break;
2339                         // | T_CLONE expr
2340                         // | T_PRINT expr
2341                         // | '@' expr
2342                         // | '+' expr
2343                         // | '-' expr
2344                         // | '!' expr
2345                         // | '~' expr
2346                         // | T_INT_CAST expr
2347                         // | T_DOUBLE_CAST expr
2348                         // | T_STRING_CAST expr
2349                         // | T_ARRAY_CAST expr
2350                         // | T_OBJECT_CAST expr
2351                         // | T_BOOL_CAST expr
2352                         // | T_UNSET_CAST expr
2353                         case TokenNameclone:
2354                         case TokenNameprint:
2355                         case TokenNameAT:
2356                         case TokenNamePLUS:
2357                         case TokenNameMINUS:
2358                         case TokenNameNOT:
2359                         case TokenNameTWIDDLE:
2360                         case TokenNameintCAST:
2361                         case TokenNamedoubleCAST:
2362                         case TokenNamestringCAST:
2363                         case TokenNamearrayCAST:
2364                         case TokenNameobjectCAST:
2365                         case TokenNameboolCAST:
2366                         case TokenNameunsetCAST:
2367                                 getNextToken();
2368                                 expr();
2369                                 break;
2370                         case TokenNameexit:
2371                                 getNextToken();
2372                                 exit_expr();
2373                                 break;
2374                         // scalar:
2375                         // T_STRING
2376                         // | T_STRING_VARNAME
2377                         // | class_constant
2378                         // | T_START_HEREDOC encaps_list T_END_HEREDOC
2379                         // | '`' encaps_list '`'
2380                         // | common_scalar
2381                         // | '`' encaps_list '`'
2382                         // case TokenNameEncapsedString0:
2383                         // scanner.encapsedStringStack.push(new Character('`'));
2384                         // getNextToken();
2385                         // try {
2386                         // if (token == TokenNameEncapsedString0) {
2387                         // } else {
2388                         // encaps_list();
2389                         // if (token != TokenNameEncapsedString0) {
2390                         // throwSyntaxError("\'`\' expected at end of string" + "(Found token: " +
2391                         // scanner.toStringAction(token) + " )");
2392                         // }
2393                         // }
2394                         // } finally {
2395                         // scanner.encapsedStringStack.pop();
2396                         // getNextToken();
2397                         // }
2398                         // break;
2399                         // // | '\'' encaps_list '\''
2400                         // case TokenNameEncapsedString1:
2401                         // scanner.encapsedStringStack.push(new Character('\''));
2402                         // getNextToken();
2403                         // try {
2404                         // exprSourceStart = scanner.getCurrentTokenStartPosition();
2405                         // if (token == TokenNameEncapsedString1) {
2406                         // expression = new
2407                         // StringLiteralSQ(scanner.getCurrentStringLiteralSource(exprSourceStart),
2408                         // exprSourceStart, scanner
2409                         // .getCurrentTokenEndPosition());
2410                         // } else {
2411                         // encaps_list();
2412                         // if (token != TokenNameEncapsedString1) {
2413                         // throwSyntaxError("\'\'\' expected at end of string" + "(Found token: "
2414                         // + scanner.toStringAction(token) + " )");
2415                         // } else {
2416                         // expression = new
2417                         // StringLiteralSQ(scanner.getCurrentStringLiteralSource(exprSourceStart),
2418                         // exprSourceStart, scanner
2419                         // .getCurrentTokenEndPosition());
2420                         // }
2421                         // }
2422                         // } finally {
2423                         // scanner.encapsedStringStack.pop();
2424                         // getNextToken();
2425                         // }
2426                         // break;
2427                         // //| '"' encaps_list '"'
2428                         // case TokenNameEncapsedString2:
2429                         // scanner.encapsedStringStack.push(new Character('"'));
2430                         // getNextToken();
2431                         // try {
2432                         // exprSourceStart = scanner.getCurrentTokenStartPosition();
2433                         // if (token == TokenNameEncapsedString2) {
2434                         // expression = new
2435                         // StringLiteralDQ(scanner.getCurrentStringLiteralSource(exprSourceStart),
2436                         // exprSourceStart, scanner
2437                         // .getCurrentTokenEndPosition());
2438                         // } else {
2439                         // encaps_list();
2440                         // if (token != TokenNameEncapsedString2) {
2441                         // throwSyntaxError("'\"' expected at end of string" + "(Found token: " +
2442                         // scanner.toStringAction(token) + " )");
2443                         // } else {
2444                         // expression = new
2445                         // StringLiteralDQ(scanner.getCurrentStringLiteralSource(exprSourceStart),
2446                         // exprSourceStart, scanner
2447                         // .getCurrentTokenEndPosition());
2448                         // }
2449                         // }
2450                         // } finally {
2451                         // scanner.encapsedStringStack.pop();
2452                         // getNextToken();
2453                         // }
2454                         // break;
2455                         case TokenNameStringDoubleQuote:
2456                                 expression = new StringLiteralDQ(scanner.getCurrentStringLiteralSource(), scanner.getCurrentTokenStartPosition(), scanner
2457                                                 .getCurrentTokenEndPosition());
2458                                 common_scalar();
2459                                 break;
2460                         case TokenNameStringSingleQuote:
2461                                 expression = new StringLiteralSQ(scanner.getCurrentStringLiteralSource(), scanner.getCurrentTokenStartPosition(), scanner
2462                                                 .getCurrentTokenEndPosition());
2463                                 common_scalar();
2464                                 break;
2465                         case TokenNameIntegerLiteral:
2466                         case TokenNameDoubleLiteral:
2467                         case TokenNameStringInterpolated:
2468                         case TokenNameFILE:
2469                         case TokenNameLINE:
2470                         case TokenNameCLASS_C:
2471                         case TokenNameMETHOD_C:
2472                         case TokenNameFUNC_C:
2473                                 common_scalar();
2474                                 break;
2475                         case TokenNameHEREDOC:
2476                                 getNextToken();
2477                                 break;
2478                         case TokenNamearray:
2479                                 // T_ARRAY '(' array_pair_list ')'
2480                                 getNextToken();
2481                                 if (token == TokenNameLPAREN) {
2482                                         getNextToken();
2483                                         if (token == TokenNameRPAREN) {
2484                                                 getNextToken();
2485                                                 break;
2486                                         }
2487                                         array_pair_list();
2488                                         if (token != TokenNameRPAREN) {
2489                                                 throwSyntaxError("')' or ',' expected after keyword 'array'" + "(Found token: " + scanner.toStringAction(token) + ")");
2490                                         }
2491                                         getNextToken();
2492                                 } else {
2493                                         throwSyntaxError("'(' expected after keyword 'array'" + "(Found token: " + scanner.toStringAction(token) + ")");
2494                                 }
2495                                 break;
2496                         case TokenNamelist:
2497                                 // | T_LIST '(' assignment_list ')' '=' expr
2498                                 getNextToken();
2499                                 if (token == TokenNameLPAREN) {
2500                                         getNextToken();
2501                                         assignment_list();
2502                                         if (token != TokenNameRPAREN) {
2503                                                 throwSyntaxError("')' expected after 'list' keyword.");
2504                                         }
2505                                         getNextToken();
2506                                         if (token != TokenNameEQUAL) {
2507                                                 throwSyntaxError("'=' expected after 'list' keyword.");
2508                                         }
2509                                         getNextToken();
2510                                         expr();
2511                                 } else {
2512                                         throwSyntaxError("'(' expected after 'list' keyword.");
2513                                 }
2514                                 break;
2515                         case TokenNamenew:
2516                                 // | T_NEW class_name_reference ctor_arguments
2517                                 getNextToken();
2518                                 Expression typeRef = class_name_reference();
2519                                 ctor_arguments();
2520                                 if (typeRef != null) {
2521                                         expression = typeRef;
2522                                 }
2523                                 break;
2524                         // | T_INC rw_variable
2525                         // | T_DEC rw_variable
2526                         case TokenNamePLUS_PLUS:
2527                         case TokenNameMINUS_MINUS:
2528                                 getNextToken();
2529                                 rw_variable();
2530                                 break;
2531                         // | variable '=' expr
2532                         // | variable '=' '&' variable
2533                         // | variable '=' '&' T_NEW class_name_reference ctor_arguments
2534                         // | variable T_PLUS_EQUAL expr
2535                         // | variable T_MINUS_EQUAL expr
2536                         // | variable T_MUL_EQUAL expr
2537                         // | variable T_DIV_EQUAL expr
2538                         // | variable T_CONCAT_EQUAL expr
2539                         // | variable T_MOD_EQUAL expr
2540                         // | variable T_AND_EQUAL expr
2541                         // | variable T_OR_EQUAL expr
2542                         // | variable T_XOR_EQUAL expr
2543                         // | variable T_SL_EQUAL expr
2544                         // | variable T_SR_EQUAL expr
2545                         // | rw_variable T_INC
2546                         // | rw_variable T_DEC
2547                         case TokenNameIdentifier:
2548                         case TokenNameVariable:
2549                         case TokenNameDOLLAR:
2550                                 Expression lhs = null;
2551                                 boolean rememberedVar = false;
2552                                 if (token == TokenNameIdentifier) {
2553                                         lhs = identifier(true, true);
2554                                         if (lhs != null) {
2555                                                 expression = lhs;
2556                                         }
2557                                 } else {
2558                                         lhs = variable(true, true);
2559                                         if (lhs != null) {
2560                                                 expression = lhs;
2561                                         }
2562                                         if (lhs != null && lhs instanceof FieldReference && token != TokenNameEQUAL && token != TokenNamePLUS_EQUAL
2563                                                         && token != TokenNameMINUS_EQUAL && token != TokenNameMULTIPLY_EQUAL && token != TokenNameDIVIDE_EQUAL
2564                                                         && token != TokenNameDOT_EQUAL && token != TokenNameREMAINDER_EQUAL && token != TokenNameAND_EQUAL
2565                                                         && token != TokenNameOR_EQUAL && token != TokenNameXOR_EQUAL && token != TokenNameRIGHT_SHIFT_EQUAL
2566                                                         && token != TokenNameLEFT_SHIFT_EQUAL) {
2567                                                 FieldReference ref = (FieldReference) lhs;
2568                                                 if (!containsVariableSet(ref.token)) {
2569                                                         if (null==initHandler || initHandler.reportError()) {
2570                                                                 problemReporter.uninitializedLocalVariable(new String(ref.token), ref.sourceStart, ref.sourceEnd,
2571                                                                         referenceContext, compilationUnit.compilationResult);
2572                                                         }
2573                                                         addVariableSet(ref.token);
2574                                                 }
2575                                         }
2576                                 }
2577                                 switch (token) {
2578                                 case TokenNameEQUAL:
2579                                         if (lhs != null && lhs instanceof FieldReference) {
2580                                                 addVariableSet(((FieldReference) lhs).token);
2581                                         }
2582                                         getNextToken();
2583                                         if (token == TokenNameAND) {
2584                                                 getNextToken();
2585                                                 if (token == TokenNamenew) {
2586                                                         // | variable '=' '&' T_NEW class_name_reference
2587                                                         // ctor_arguments
2588                                                         getNextToken();
2589                                                         SingleTypeReference classRef = class_name_reference();
2590                                                         ctor_arguments();
2591                                                         if (classRef != null) {
2592                                                                 if (lhs != null && lhs instanceof FieldReference) {
2593                                                                         // example:
2594                                                                         // $var = & new Object();
2595                                                                         if (fMethodVariables != null) {
2596                                                                                 VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
2597                                                                                 lhsInfo.reference = classRef;
2598                                                                                 lhsInfo.typeIdentifier = classRef.token;
2599                                                                                 fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2600                                                                                 rememberedVar = true;
2601                                                                         }
2602                                                                 }
2603                                                         }
2604                                                 } else {
2605                                                         Expression rhs = variable(false, false);
2606                                                         if (rhs != null && rhs instanceof FieldReference && lhs != null && lhs instanceof FieldReference) {
2607                                                                 // example:
2608                                                                 // $var = &$ref;
2609                                                                 if (fMethodVariables != null) {
2610                                                                         VariableInfo rhsInfo = (VariableInfo) fMethodVariables.get(((FieldReference) rhs).token);
2611                                                                         if (rhsInfo != null && rhsInfo.reference != null) {
2612                                                                                 VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
2613                                                                                 lhsInfo.reference = rhsInfo.reference;
2614                                                                                 lhsInfo.typeIdentifier = rhsInfo.typeIdentifier;
2615                                                                                 fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2616                                                                                 rememberedVar = true;
2617                                                                         }
2618                                                                 }
2619                                                         }
2620                                                 }
2621                                         } else {
2622                                                 Expression rhs = expr();
2623                                                 if (lhs != null && lhs instanceof FieldReference) {
2624                                                         if (rhs != null && rhs instanceof FieldReference) {
2625                                                                 // example:
2626                                                                 // $var = $ref;
2627                                                                 if (fMethodVariables != null) {
2628                                                                         VariableInfo rhsInfo = (VariableInfo) fMethodVariables.get(((FieldReference) rhs).token);
2629                                                                         if (rhsInfo != null && rhsInfo.reference != null) {
2630                                                                                 VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
2631                                                                                 lhsInfo.reference = rhsInfo.reference;
2632                                                                                 lhsInfo.typeIdentifier = rhsInfo.typeIdentifier;
2633                                                                                 fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2634                                                                                 rememberedVar = true;
2635                                                                         }
2636                                                                 }
2637                                                         } else if (rhs != null && rhs instanceof SingleTypeReference) {
2638                                                                 // example:
2639                                                                 // $var = new Object();
2640                                                                 if (fMethodVariables != null) {
2641                                                                         VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
2642                                                                         lhsInfo.reference = (SingleTypeReference) rhs;
2643                                                                         lhsInfo.typeIdentifier = ((SingleTypeReference) rhs).token;
2644                                                                         fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2645                                                                         rememberedVar = true;
2646                                                                 }
2647                                                         }
2648                                                 }
2649                                         }
2650                                         if (rememberedVar == false && lhs != null && lhs instanceof FieldReference) {
2651                                                 if (fMethodVariables != null) {
2652                                                         VariableInfo lhsInfo = new VariableInfo(((FieldReference) lhs).sourceStart);
2653                                                         fMethodVariables.put(new String(((FieldReference) lhs).token), lhsInfo);
2654                                                 }
2655                                         }
2656                                         break;
2657                                 case TokenNamePLUS_EQUAL:
2658                                 case TokenNameMINUS_EQUAL:
2659                                 case TokenNameMULTIPLY_EQUAL:
2660                                 case TokenNameDIVIDE_EQUAL:
2661                                 case TokenNameDOT_EQUAL:
2662                                 case TokenNameREMAINDER_EQUAL:
2663                                 case TokenNameAND_EQUAL:
2664                                 case TokenNameOR_EQUAL:
2665                                 case TokenNameXOR_EQUAL:
2666                                 case TokenNameRIGHT_SHIFT_EQUAL:
2667                                 case TokenNameLEFT_SHIFT_EQUAL:
2668                                         if (lhs != null && lhs instanceof FieldReference) {
2669                                                 addVariableSet(((FieldReference) lhs).token);
2670                                         }
2671                                         getNextToken();
2672                                         expr();
2673                                         break;
2674                                 case TokenNamePLUS_PLUS:
2675                                 case TokenNameMINUS_MINUS:
2676                                         getNextToken();
2677                                         break;
2678                                 default:
2679                                         if (!only_variable) {
2680                                                 throwSyntaxError("Variable expression not allowed (found token '" + scanner.toStringAction(token) + "').");
2681                                         }
2682                                         if (lhs != null) {
2683                                                 expression = lhs;
2684                                         }
2685                                 }
2686                                 break;
2687                         default:
2688                                 if (token != TokenNameINLINE_HTML) {
2689                                         if (token > TokenNameKEYWORD) {
2690                                                 getNextToken();
2691                                                 break;
2692                                         } else {
2693                                                 // System.out.println(scanner.getCurrentTokenStartPosition());
2694                                                 // System.out.println(scanner.getCurrentTokenEndPosition());
2695
2696                                                 throwSyntaxError("Error in expression (found token '" + scanner.toStringAction(token) + "').");
2697                                         }
2698                                 }
2699                                 return expression;
2700                         }
2701                         if (Scanner.TRACE) {
2702                                 System.out.println("TRACE: expr_without_variable() PART 2");
2703                         }
2704                         // | expr T_BOOLEAN_OR expr
2705                         // | expr T_BOOLEAN_AND expr
2706                         // | expr T_LOGICAL_OR expr
2707                         // | expr T_LOGICAL_AND expr
2708                         // | expr T_LOGICAL_XOR expr
2709                         // | expr '|' expr
2710                         // | expr '&' expr
2711                         // | expr '^' expr
2712                         // | expr '.' expr
2713                         // | expr '+' expr
2714                         // | expr '-' expr
2715                         // | expr '*' expr
2716                         // | expr '/' expr
2717                         // | expr '%' expr
2718                         // | expr T_SL expr
2719                         // | expr T_SR expr
2720                         // | expr T_IS_IDENTICAL expr
2721                         // | expr T_IS_NOT_IDENTICAL expr
2722                         // | expr T_IS_EQUAL expr
2723                         // | expr T_IS_NOT_EQUAL expr
2724                         // | expr '<' expr
2725                         // | expr T_IS_SMALLER_OR_EQUAL expr
2726                         // | expr '>' expr
2727                         // | expr T_IS_GREATER_OR_EQUAL expr
2728                         while (true) {
2729                                 switch (token) {
2730                                 case TokenNameOR_OR:
2731                                         getNextToken();
2732                                         expression = new OR_OR_Expression(expression, expr(), token);
2733                                         break;
2734                                 case TokenNameAND_AND:
2735                                         getNextToken();
2736                                         expression = new AND_AND_Expression(expression, expr(), token);
2737                                         break;
2738                                 case TokenNameEQUAL_EQUAL:
2739                                         getNextToken();
2740                                         expression = new EqualExpression(expression, expr(), token);
2741                                         break;
2742                                 case TokenNameand:
2743                                 case TokenNameor:
2744                                 case TokenNamexor:
2745                                 case TokenNameAND:
2746                                 case TokenNameOR:
2747                                 case TokenNameXOR:
2748                                 case TokenNameDOT:
2749                                 case TokenNamePLUS:
2750                                 case TokenNameMINUS:
2751                                 case TokenNameMULTIPLY:
2752                                 case TokenNameDIVIDE:
2753                                 case TokenNameREMAINDER:
2754                                 case TokenNameLEFT_SHIFT:
2755                                 case TokenNameRIGHT_SHIFT:
2756                                 case TokenNameEQUAL_EQUAL_EQUAL:
2757                                 case TokenNameNOT_EQUAL_EQUAL:
2758                                 case TokenNameNOT_EQUAL:
2759                                 case TokenNameLESS:
2760                                 case TokenNameLESS_EQUAL:
2761                                 case TokenNameGREATER:
2762                                 case TokenNameGREATER_EQUAL:
2763                                         getNextToken();
2764                                         expression = new BinaryExpression(expression, expr(), token);
2765                                         break;
2766                                 // | expr T_INSTANCEOF class_name_reference
2767                                 // | expr '?' expr ':' expr
2768                                 case TokenNameinstanceof:
2769                                         getNextToken();
2770                                         TypeReference classRef = class_name_reference();
2771                                         if (classRef != null) {
2772                                                 expression = new InstanceOfExpression(expression, classRef, OperatorIds.INSTANCEOF);
2773                                                 expression.sourceStart = exprSourceStart;
2774                                                 expression.sourceEnd = scanner.getCurrentTokenEndPosition();
2775                                         }
2776                                         break;
2777                                 case TokenNameQUESTION:
2778                                         getNextToken();
2779                                         Expression valueIfTrue = expr();
2780                                         if (token != TokenNameCOLON) {
2781                                                 throwSyntaxError("':' expected in conditional expression.");
2782                                         }
2783                                         getNextToken();
2784                                         Expression valueIfFalse = expr();
2785
2786                                         expression = new ConditionalExpression(expression, valueIfTrue, valueIfFalse);
2787                                         break;
2788                                 default:
2789                                         return expression;
2790                                 }
2791                         }
2792                 } catch (SyntaxError e) {
2793                         // try to find next token after expression with errors:
2794                         if (token == TokenNameSEMICOLON) {
2795                                 getNextToken();
2796                                 return expression;
2797                         }
2798                         if (token == TokenNameRBRACE || token == TokenNameRPAREN || token == TokenNameRBRACKET) {
2799                                 getNextToken();
2800                                 return expression;
2801                         }
2802                         throw e;
2803                 }
2804         }
2805
2806         private SingleTypeReference class_name_reference() {
2807                 // class_name_reference:
2808                 // T_STRING
2809                 // | dynamic_class_name_reference
2810                 SingleTypeReference ref = null;
2811                 if (Scanner.TRACE) {
2812                         System.out.println("TRACE: class_name_reference()");
2813                 }
2814                 if (token == TokenNameIdentifier) {
2815                         ref = new SingleTypeReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition());
2816                         getNextToken();
2817                 } else {
2818                         ref = null;
2819                         dynamic_class_name_reference();
2820                 }
2821                 return ref;
2822         }
2823
2824         private void dynamic_class_name_reference() {
2825                 // dynamic_class_name_reference:
2826                 // base_variable T_OBJECT_OPERATOR object_property
2827                 // dynamic_class_name_variable_properties
2828                 // | base_variable
2829                 if (Scanner.TRACE) {
2830                         System.out.println("TRACE: dynamic_class_name_reference()");
2831                 }
2832                 base_variable(true);
2833                 if (token == TokenNameMINUS_GREATER) {
2834                         getNextToken();
2835                         object_property();
2836                         dynamic_class_name_variable_properties();
2837                 }
2838         }
2839
2840         private void dynamic_class_name_variable_properties() {
2841                 // dynamic_class_name_variable_properties:
2842                 // dynamic_class_name_variable_properties
2843                 // dynamic_class_name_variable_property
2844                 // | /* empty */
2845                 if (Scanner.TRACE) {
2846                         System.out.println("TRACE: dynamic_class_name_variable_properties()");
2847                 }
2848                 while (token == TokenNameMINUS_GREATER) {
2849                         dynamic_class_name_variable_property();
2850                 }
2851         }
2852
2853         private void dynamic_class_name_variable_property() {
2854                 // dynamic_class_name_variable_property:
2855                 // T_OBJECT_OPERATOR object_property
2856                 if (Scanner.TRACE) {
2857                         System.out.println("TRACE: dynamic_class_name_variable_property()");
2858                 }
2859                 if (token == TokenNameMINUS_GREATER) {
2860                         getNextToken();
2861                         object_property();
2862                 }
2863         }
2864
2865         private void ctor_arguments() {
2866                 // ctor_arguments:
2867                 // /* empty */
2868                 // | '(' function_call_parameter_list ')'
2869                 if (token == TokenNameLPAREN) {
2870                         getNextToken();
2871                         if (token == TokenNameRPAREN) {
2872                                 getNextToken();
2873                                 return;
2874                         }
2875                         non_empty_function_call_parameter_list();
2876                         if (token != TokenNameRPAREN) {
2877                                 throwSyntaxError("')' expected in ctor_arguments.");
2878                         }
2879                         getNextToken();
2880                 }
2881         }
2882
2883         private void assignment_list() {
2884                 // assignment_list:
2885                 // assignment_list ',' assignment_list_element
2886                 // | assignment_list_element
2887                 while (true) {
2888                         assignment_list_element();
2889                         if (token != TokenNameCOMMA) {
2890                                 break;
2891                         }
2892                         getNextToken();
2893                 }
2894         }
2895
2896         private void assignment_list_element() {
2897                 // assignment_list_element:
2898                 // variable
2899                 // | T_LIST '(' assignment_list ')'
2900                 // | /* empty */
2901                 if (token == TokenNameVariable) {
2902                         variable(true, false);
2903                 } else if (token == TokenNameDOLLAR) {
2904                         variable(false, false);
2905                 } else if (token == TokenNameIdentifier) {
2906                         identifier(true, true);
2907                 } else {
2908                         if (token == TokenNamelist) {
2909                                 getNextToken();
2910                                 if (token == TokenNameLPAREN) {
2911                                         getNextToken();
2912                                         assignment_list();
2913                                         if (token != TokenNameRPAREN) {
2914                                                 throwSyntaxError("')' expected after 'list' keyword.");
2915                                         }
2916                                         getNextToken();
2917                                 } else {
2918                                         throwSyntaxError("'(' expected after 'list' keyword.");
2919                                 }
2920                         }
2921                 }
2922         }
2923
2924         private void array_pair_list() {
2925                 // array_pair_list:
2926                 // /* empty */
2927                 // | non_empty_array_pair_list possible_comma
2928                 non_empty_array_pair_list();
2929                 if (token == TokenNameCOMMA) {
2930                         getNextToken();
2931                 }
2932         }
2933
2934         private void non_empty_array_pair_list() {
2935                 // non_empty_array_pair_list:
2936                 // non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr
2937                 // | non_empty_array_pair_list ',' expr
2938                 // | expr T_DOUBLE_ARROW expr
2939                 // | expr
2940                 // | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable
2941                 // | non_empty_array_pair_list ',' '&' w_variable
2942                 // | expr T_DOUBLE_ARROW '&' w_variable
2943                 // | '&' w_variable
2944                 while (true) {
2945                         if (token == TokenNameAND) {
2946                                 getNextToken();
2947                                 variable(true, false);
2948                         } else {
2949                                 expr();
2950                                 if (token == TokenNameAND) {
2951                                         getNextToken();
2952                                         variable(true, false);
2953                                 } else if (token == TokenNameEQUAL_GREATER) {
2954                                         getNextToken();
2955                                         if (token == TokenNameAND) {
2956                                                 getNextToken();
2957                                                 variable(true, false);
2958                                         } else {
2959                                                 expr();
2960                                         }
2961                                 }
2962                         }
2963                         if (token != TokenNameCOMMA) {
2964                                 return;
2965                         }
2966                         getNextToken();
2967                         if (token == TokenNameRPAREN) {
2968                                 return;
2969                         }
2970                 }
2971         }
2972
2973         // private void variableList() {
2974         // do {
2975         // variable();
2976         // if (token == TokenNameCOMMA) {
2977         // getNextToken();
2978         // } else {
2979         // break;
2980         // }
2981         // } while (true);
2982         // }
2983         private Expression variable_without_objects(boolean lefthandside, boolean ignoreVar) {
2984                 // variable_without_objects:
2985                 // reference_variable
2986                 // | simple_indirect_reference reference_variable
2987                 if (Scanner.TRACE) {
2988                         System.out.println("TRACE: variable_without_objects()");
2989                 }
2990                 while (token == TokenNameDOLLAR) {
2991                         getNextToken();
2992                 }
2993                 return reference_variable(lefthandside, ignoreVar);
2994         }
2995
2996         private Expression function_call(boolean lefthandside, boolean ignoreVar) {
2997                 // function_call:
2998                 // T_STRING '(' function_call_parameter_list ')'
2999                 // | class_constant '(' function_call_parameter_list ')'
3000                 // | static_member '(' function_call_parameter_list ')'
3001                 // | variable_without_objects '(' function_call_parameter_list ')'
3002                 char[] defineName = null;
3003                 char[] ident = null;
3004                 int startPos = 0;
3005                 int endPos = 0;
3006                 Expression ref = null;
3007                 if (Scanner.TRACE) {
3008                         System.out.println("TRACE: function_call()");
3009                 }
3010                 if (token == TokenNameIdentifier) {
3011                         ident = scanner.getCurrentIdentifierSource();
3012                         defineName = ident;
3013                         startPos = scanner.getCurrentTokenStartPosition();
3014                         endPos = scanner.getCurrentTokenEndPosition();
3015                         getNextToken();
3016                         switch (token) {
3017                         case TokenNamePAAMAYIM_NEKUDOTAYIM:
3018                                 // static member:
3019                                 defineName = null;
3020                                 getNextToken();
3021                                 if (token == TokenNameIdentifier) {
3022                                         // class _constant
3023                                         getNextToken();
3024                                 } else {
3025                                         // static member:
3026                                         variable_without_objects(true, false);
3027                                 }
3028                                 break;
3029                         }
3030                 } else {
3031                         ref = variable_without_objects(lefthandside, ignoreVar);
3032                 }
3033                 if (token != TokenNameLPAREN) {
3034                         if (defineName != null) {
3035                                 // does this identifier contain only uppercase characters?
3036                                 if (defineName.length == 3) {
3037                                         if (defineName[0] == 'd' && defineName[1] == 'i' && defineName[2] == 'e') {
3038                                                 defineName = null;
3039                                         }
3040                                 } else if (defineName.length == 4) {
3041                                         if (defineName[0] == 't' && defineName[1] == 'r' && defineName[2] == 'u' && defineName[3] == 'e') {
3042                                                 defineName = null;
3043                                         } else if (defineName[0] == 'n' && defineName[1] == 'u' && defineName[2] == 'l' && defineName[3] == 'l') {
3044                                                 defineName = null;
3045                                         }
3046                                 } else if (defineName.length == 5) {
3047                                         if (defineName[0] == 'f' && defineName[1] == 'a' && defineName[2] == 'l' && defineName[3] == 's' && defineName[4] == 'e') {
3048                                                 defineName = null;
3049                                         }
3050                                 }
3051                                 if (defineName != null) {
3052                                         for (int i = 0; i < defineName.length; i++) {
3053                                                 if (Character.isLowerCase(defineName[i])) {
3054                                                         problemReporter.phpUppercaseIdentifierWarning(startPos, endPos, referenceContext, compilationUnit.compilationResult);
3055                                                         break;
3056                                                 }
3057                                         }
3058                                 }
3059                         }
3060                 } else {
3061                         getNextToken();
3062                         if (token == TokenNameRPAREN) {
3063                                 getNextToken();
3064                                 return ref;
3065                         }
3066                         non_empty_function_call_parameter_list();
3067                         if (token != TokenNameRPAREN) {
3068                                 String functionName;
3069                                 if (ident == null) {
3070                                         functionName = new String(" ");
3071                                 } else {
3072                                         functionName = new String(ident);
3073                                 }
3074                                 throwSyntaxError("')' expected in function call (" + functionName + ").");
3075                         }
3076                         getNextToken();
3077                 }
3078                 return ref;
3079         }
3080
3081         private void non_empty_function_call_parameter_list() {
3082                 this.non_empty_function_call_parameter_list(null);
3083         }
3084
3085         // private void function_call_parameter_list() {
3086         // function_call_parameter_list:
3087         // non_empty_function_call_parameter_list { $$ = $1; }
3088         // | /* empty */
3089         // }
3090         private void non_empty_function_call_parameter_list(String functionName) {
3091                 // non_empty_function_call_parameter_list:
3092                 // expr_without_variable
3093                 // | variable
3094                 // | '&' w_variable
3095                 // | non_empty_function_call_parameter_list ',' expr_without_variable
3096                 // | non_empty_function_call_parameter_list ',' variable
3097                 // | non_empty_function_call_parameter_list ',' '&' w_variable
3098                 if (Scanner.TRACE) {
3099                         System.out.println("TRACE: non_empty_function_call_parameter_list()");
3100                 }
3101                 UninitializedVariableHandler initHandler = new UninitializedVariableHandler();
3102                 initHandler.setFunctionName(functionName);
3103                 while (true) {
3104                         initHandler.incrementArgumentCount();
3105                         if (token == TokenNameAND) {
3106                                 getNextToken();
3107                                 w_variable(true);
3108                         } else {
3109                                 // if (token == TokenNameIdentifier || token ==
3110                                 // TokenNameVariable
3111                                 // || token == TokenNameDOLLAR) {
3112                                 // variable();
3113                                 // } else {
3114                                 expr_without_variable(true, initHandler);
3115                                 // }
3116                         }
3117                         if (token != TokenNameCOMMA) {
3118                                 break;
3119                         }
3120                         getNextToken();
3121                 }
3122         }
3123
3124         private void fully_qualified_class_name() {
3125                 if (token == TokenNameIdentifier) {
3126                         getNextToken();
3127                 } else {
3128                         throwSyntaxError("Class name expected.");
3129                 }
3130         }
3131
3132         private void static_member() {
3133                 // static_member:
3134                 // fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM
3135                 // variable_without_objects
3136                 if (Scanner.TRACE) {
3137                         System.out.println("TRACE: static_member()");
3138                 }
3139                 fully_qualified_class_name();
3140                 if (token != TokenNamePAAMAYIM_NEKUDOTAYIM) {
3141                         throwSyntaxError("'::' expected after class name (static_member).");
3142                 }
3143                 getNextToken();
3144                 variable_without_objects(false, false);
3145         }
3146
3147         private Expression base_variable_with_function_calls(boolean lefthandside, boolean ignoreVar) {
3148                 // base_variable_with_function_calls:
3149                 // base_variable
3150                 // | function_call
3151                 if (Scanner.TRACE) {
3152                         System.out.println("TRACE: base_variable_with_function_calls()");
3153                 }
3154                 return function_call(lefthandside, ignoreVar);
3155         }
3156
3157         private Expression base_variable(boolean lefthandside) {
3158                 // base_variable:
3159                 // reference_variable
3160                 // | simple_indirect_reference reference_variable
3161                 // | static_member
3162                 Expression ref = null;
3163                 if (Scanner.TRACE) {
3164                         System.out.println("TRACE: base_variable()");
3165                 }
3166                 if (token == TokenNameIdentifier) {
3167                         static_member();
3168                 } else {
3169                         while (token == TokenNameDOLLAR) {
3170                                 getNextToken();
3171                         }
3172                         reference_variable(lefthandside, false);
3173                 }
3174                 return ref;
3175         }
3176
3177         // private void simple_indirect_reference() {
3178         // // simple_indirect_reference:
3179         // // '$'
3180         // //| simple_indirect_reference '$'
3181         // }
3182         private Expression reference_variable(boolean lefthandside, boolean ignoreVar) {
3183                 // reference_variable:
3184                 // reference_variable '[' dim_offset ']'
3185                 // | reference_variable '{' expr '}'
3186                 // | compound_variable
3187                 Expression ref = null;
3188                 if (Scanner.TRACE) {
3189                         System.out.println("TRACE: reference_variable()");
3190                 }
3191                 ref = compound_variable(lefthandside, ignoreVar);
3192                 while (true) {
3193                         if (token == TokenNameLBRACE) {
3194                                 ref = null;
3195                                 getNextToken();
3196                                 expr();
3197                                 if (token != TokenNameRBRACE) {
3198                                         throwSyntaxError("'}' expected in reference variable.");
3199                                 }
3200                                 getNextToken();
3201                         } else if (token == TokenNameLBRACKET) {
3202                                 // To remove "ref = null;" here, is probably better than the patch
3203                                 // commented in #1368081 - axelcl
3204                                 getNextToken();
3205                                 if (token != TokenNameRBRACKET) {
3206                                         expr();
3207                                         // dim_offset();
3208                                         if (token != TokenNameRBRACKET) {
3209                                                 throwSyntaxError("']' expected in reference variable.");
3210                                         }
3211                                 }
3212                                 getNextToken();
3213                         } else {
3214                                 break;
3215                         }
3216                 }
3217                 return ref;
3218         }
3219
3220         private Expression compound_variable(boolean lefthandside, boolean ignoreVar) {
3221                 // compound_variable:
3222                 // T_VARIABLE
3223                 // | '$' '{' expr '}'
3224                 if (Scanner.TRACE) {
3225                         System.out.println("TRACE: compound_variable()");
3226                 }
3227                 if (token == TokenNameVariable) {
3228                         if (!lefthandside) {
3229                                 if (!containsVariableSet()) {
3230                                         // reportSyntaxError("The local variable " + new
3231                                         // String(scanner.getCurrentIdentifierSource())
3232                                         // + " may not have been initialized");
3233                                         problemReporter.uninitializedLocalVariable(new String(scanner.getCurrentIdentifierSource()), scanner
3234                                                         .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), referenceContext,
3235                                                         compilationUnit.compilationResult);
3236                                 }
3237                         } else {
3238                                 if (!ignoreVar) {
3239                                         addVariableSet();
3240                                 }
3241                         }
3242                         FieldReference ref = new FieldReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition());
3243                         getNextToken();
3244                         return ref;
3245                 } else {
3246                         // because of simple_indirect_reference
3247                         while (token == TokenNameDOLLAR) {
3248                                 getNextToken();
3249                         }
3250                         if (token != TokenNameLBRACE) {
3251                                 reportSyntaxError("'{' expected after compound variable token '$'.");
3252                                 return null;
3253                         }
3254                         getNextToken();
3255                         expr();
3256                         if (token != TokenNameRBRACE) {
3257                                 throwSyntaxError("'}' expected after compound variable token '$'.");
3258                         }
3259                         getNextToken();
3260                 }
3261                 return null;
3262         } // private void dim_offset() { // // dim_offset: // // /* empty */
3263
3264         // // | expr
3265         // expr();
3266         // }
3267         private void object_property() {
3268                 // object_property:
3269                 // object_dim_list
3270                 // | variable_without_objects
3271                 if (Scanner.TRACE) {
3272                         System.out.println("TRACE: object_property()");
3273                 }
3274                 if (token == TokenNameVariable || token == TokenNameDOLLAR) {
3275                         variable_without_objects(false, false);
3276                 } else {
3277                         object_dim_list();
3278                 }
3279         }
3280
3281         private void object_dim_list() {
3282                 // object_dim_list:
3283                 // object_dim_list '[' dim_offset ']'
3284                 // | object_dim_list '{' expr '}'
3285                 // | variable_name
3286                 if (Scanner.TRACE) {
3287                         System.out.println("TRACE: object_dim_list()");
3288                 }
3289                 variable_name();
3290                 while (true) {
3291                         if (token == TokenNameLBRACE) {
3292                                 getNextToken();
3293                                 expr();
3294                                 if (token != TokenNameRBRACE) {
3295                                         throwSyntaxError("'}' expected in object_dim_list.");
3296                                 }
3297                                 getNextToken();
3298                         } else if (token == TokenNameLBRACKET) {
3299                                 getNextToken();
3300                                 if (token == TokenNameRBRACKET) {
3301                                         getNextToken();
3302                                         continue;
3303                                 }
3304                                 expr();
3305                                 if (token != TokenNameRBRACKET) {
3306                                         throwSyntaxError("']' expected in object_dim_list.");
3307                                 }
3308                                 getNextToken();
3309                         } else {
3310                                 break;
3311                         }
3312                 }
3313         }
3314
3315         private void variable_name() {
3316                 // variable_name:
3317                 // T_STRING
3318                 // | '{' expr '}'
3319                 if (Scanner.TRACE) {
3320                         System.out.println("TRACE: variable_name()");
3321                 }
3322                 if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
3323                         if (token > TokenNameKEYWORD) {
3324                                 // TODO show a warning "Keyword used as variable" ?
3325                         }
3326                         getNextToken();
3327                 } else {
3328                         if (token != TokenNameLBRACE) {
3329                                 throwSyntaxError("'{' expected in variable name.");
3330                         }
3331                         getNextToken();
3332                         expr();
3333                         if (token != TokenNameRBRACE) {
3334                                 throwSyntaxError("'}' expected in variable name.");
3335                         }
3336                         getNextToken();
3337                 }
3338         }
3339
3340         private void r_variable() {
3341                 variable(false, false);
3342         }
3343
3344         private void w_variable(boolean lefthandside) {
3345                 variable(lefthandside, false);
3346         }
3347
3348         private void rw_variable() {
3349                 variable(false, false);
3350         }
3351
3352         private Expression variable(boolean lefthandside, boolean ignoreVar) {
3353                 // variable:
3354                 // base_variable_with_function_calls T_OBJECT_OPERATOR
3355                 // object_property method_or_not variable_properties
3356                 // | base_variable_with_function_calls
3357                 Expression ref = base_variable_with_function_calls(lefthandside, ignoreVar);
3358                 if (token == TokenNameMINUS_GREATER) {
3359                         ref = null;
3360                         getNextToken();
3361                         object_property();
3362                         method_or_not();
3363                         variable_properties();
3364                 }
3365                 return ref;
3366         }
3367
3368         private void variable_properties() {
3369                 // variable_properties:
3370                 // variable_properties variable_property
3371                 // | /* empty */
3372                 while (token == TokenNameMINUS_GREATER) {
3373                         variable_property();
3374                 }
3375         }
3376
3377         private void variable_property() {
3378                 // variable_property:
3379                 // T_OBJECT_OPERATOR object_property method_or_not
3380                 if (Scanner.TRACE) {
3381                         System.out.println("TRACE: variable_property()");
3382                 }
3383                 if (token == TokenNameMINUS_GREATER) {
3384                         getNextToken();
3385                         object_property();
3386                         method_or_not();
3387                 } else {
3388                         throwSyntaxError("'->' expected in variable_property.");
3389                 }
3390         }
3391
3392         private Expression identifier(boolean lefthandside, boolean ignoreVar) {
3393                 // variable:
3394                 // base_variable_with_function_calls T_OBJECT_OPERATOR
3395                 // object_property method_or_not variable_properties
3396                 // | base_variable_with_function_calls
3397
3398                 // Expression ref = function_call(lefthandside, ignoreVar);
3399
3400                 // function_call:
3401                 // T_STRING '(' function_call_parameter_list ')'
3402                 // | class_constant '(' function_call_parameter_list ')'
3403                 // | static_member '(' function_call_parameter_list ')'
3404                 // | variable_without_objects '(' function_call_parameter_list ')'
3405                 char[] defineName = null;
3406                 char[] ident = null;
3407                 int startPos = 0;
3408                 int endPos = 0;
3409                 Expression ref = null;
3410                 if (Scanner.TRACE) {
3411                         System.out.println("TRACE: function_call()");
3412                 }
3413                 if (token == TokenNameIdentifier) {
3414                         ident = scanner.getCurrentIdentifierSource();
3415                         defineName = ident;
3416                         startPos = scanner.getCurrentTokenStartPosition();
3417                         endPos = scanner.getCurrentTokenEndPosition();
3418                         getNextToken();
3419
3420                         if (token == TokenNameEQUAL || token == TokenNamePLUS_EQUAL || token == TokenNameMINUS_EQUAL
3421                                         || token == TokenNameMULTIPLY_EQUAL || token == TokenNameDIVIDE_EQUAL || token == TokenNameDOT_EQUAL
3422                                         || token == TokenNameREMAINDER_EQUAL || token == TokenNameAND_EQUAL || token == TokenNameOR_EQUAL
3423                                         || token == TokenNameXOR_EQUAL || token == TokenNameRIGHT_SHIFT_EQUAL || token == TokenNameLEFT_SHIFT_EQUAL) {
3424                                 String error = "Assignment operator '" + scanner.toStringAction(token) + "' not allowed after identifier '"
3425                                                 + new String(ident) + "' (use 'define(...)' to define constants).";
3426                                 reportSyntaxError(error);
3427                         }
3428
3429                         switch (token) {
3430                         case TokenNamePAAMAYIM_NEKUDOTAYIM:
3431                                 // static member:
3432                                 defineName = null;
3433                                 getNextToken();
3434                                 if (token == TokenNameIdentifier) {
3435                                         // class _constant
3436                                         getNextToken();
3437                                 } else {
3438                                         // static member:
3439                                         variable_without_objects(true, false);
3440                                 }
3441                                 break;
3442                         }
3443                 } else {
3444                         ref = variable_without_objects(lefthandside, ignoreVar);
3445                 }
3446                 if (token != TokenNameLPAREN) {
3447                         if (defineName != null) {
3448                                 // does this identifier contain only uppercase characters?
3449                                 if (defineName.length == 3) {
3450                                         if (defineName[0] == 'd' && defineName[1] == 'i' && defineName[2] == 'e') {
3451                                                 defineName = null;
3452                                         }
3453                                 } else if (defineName.length == 4) {
3454                                         if (defineName[0] == 't' && defineName[1] == 'r' && defineName[2] == 'u' && defineName[3] == 'e') {
3455                                                 defineName = null;
3456                                         } else if (defineName[0] == 'n' && defineName[1] == 'u' && defineName[2] == 'l' && defineName[3] == 'l') {
3457                                                 defineName = null;
3458                                         }
3459                                 } else if (defineName.length == 5) {
3460                                         if (defineName[0] == 'f' && defineName[1] == 'a' && defineName[2] == 'l' && defineName[3] == 's' && defineName[4] == 'e') {
3461                                                 defineName = null;
3462                                         }
3463                                 }
3464                                 if (defineName != null) {
3465                                         for (int i = 0; i < defineName.length; i++) {
3466                                                 if (Character.isLowerCase(defineName[i])) {
3467                                                         problemReporter.phpUppercaseIdentifierWarning(startPos, endPos, referenceContext, compilationUnit.compilationResult);
3468                                                         break;
3469                                                 }
3470                                         }
3471                                 }
3472                         }
3473                         // TODO is this ok ?
3474                         // return ref;
3475                         // throwSyntaxError("'(' expected in function call.");
3476                 } else {
3477                         getNextToken();
3478
3479                         if (token == TokenNameRPAREN) {
3480                                 getNextToken();
3481                                 ref = null;
3482                         } else {
3483                                 String functionName;
3484                                 if (ident == null) {
3485                                         functionName = new String(" ");
3486                                 } else {
3487                                         functionName = new String(ident);
3488                                 }
3489                                 non_empty_function_call_parameter_list(functionName);
3490                                 if (token != TokenNameRPAREN) {
3491                                         throwSyntaxError("')' expected in function call (" + functionName + ").");
3492                                 }
3493                                 getNextToken();
3494                         }
3495                 }
3496                 if (token == TokenNameMINUS_GREATER) {
3497                         ref = null;
3498                         getNextToken();
3499                         object_property();
3500                         method_or_not();
3501                         variable_properties();
3502                 }
3503                 return ref;
3504         }
3505
3506         private void method_or_not() {
3507                 // method_or_not:
3508                 // '(' function_call_parameter_list ')'
3509                 // | /* empty */
3510                 if (Scanner.TRACE) {
3511                         System.out.println("TRACE: method_or_not()");
3512                 }
3513                 if (token == TokenNameLPAREN) {
3514                         getNextToken();
3515                         if (token == TokenNameRPAREN) {
3516                                 getNextToken();
3517                                 return;
3518                         }
3519                         non_empty_function_call_parameter_list();
3520                         if (token != TokenNameRPAREN) {
3521                                 throwSyntaxError("')' expected in method_or_not.");
3522                         }
3523                         getNextToken();
3524                 }
3525         }
3526
3527         private void exit_expr() {
3528                 // /* empty */
3529                 // | '(' ')'
3530                 // | '(' expr ')'
3531                 if (token != TokenNameLPAREN) {
3532                         return;
3533                 }
3534                 getNextToken();
3535                 if (token == TokenNameRPAREN) {
3536                         getNextToken();
3537                         return;
3538                 }
3539                 expr();
3540                 if (token != TokenNameRPAREN) {
3541                         throwSyntaxError("')' expected after keyword 'exit'");
3542                 }
3543                 getNextToken();
3544         }
3545
3546         // private void encaps_list() {
3547         // // encaps_list encaps_var
3548         // // | encaps_list T_STRING
3549         // // | encaps_list T_NUM_STRING
3550         // // | encaps_list T_ENCAPSED_AND_WHITESPACE
3551         // // | encaps_list T_CHARACTER
3552         // // | encaps_list T_BAD_CHARACTER
3553         // // | encaps_list '['
3554         // // | encaps_list ']'
3555         // // | encaps_list '{'
3556         // // | encaps_list '}'
3557         // // | encaps_list T_OBJECT_OPERATOR
3558         // // | /* empty */
3559         // while (true) {
3560         // switch (token) {
3561         // case TokenNameSTRING:
3562         // getNextToken();
3563         // break;
3564         // case TokenNameLBRACE:
3565         // // scanner.encapsedStringStack.pop();
3566         // getNextToken();
3567         // break;
3568         // case TokenNameRBRACE:
3569         // // scanner.encapsedStringStack.pop();
3570         // getNextToken();
3571         // break;
3572         // case TokenNameLBRACKET:
3573         // // scanner.encapsedStringStack.pop();
3574         // getNextToken();
3575         // break;
3576         // case TokenNameRBRACKET:
3577         // // scanner.encapsedStringStack.pop();
3578         // getNextToken();
3579         // break;
3580         // case TokenNameMINUS_GREATER:
3581         // // scanner.encapsedStringStack.pop();
3582         // getNextToken();
3583         // break;
3584         // case TokenNameVariable:
3585         // case TokenNameDOLLAR_LBRACE:
3586         // case TokenNameLBRACE_DOLLAR:
3587         // encaps_var();
3588         // break;
3589         // default:
3590         // char encapsedChar = ((Character)
3591         // scanner.encapsedStringStack.peek()).charValue();
3592         // if (encapsedChar == '$') {
3593         // scanner.encapsedStringStack.pop();
3594         // encapsedChar = ((Character)
3595         // scanner.encapsedStringStack.peek()).charValue();
3596         // switch (encapsedChar) {
3597         // case '`':
3598         // if (token == TokenNameEncapsedString0) {
3599         // return;
3600         // }
3601         // token = TokenNameSTRING;
3602         // continue;
3603         // case '\'':
3604         // if (token == TokenNameEncapsedString1) {
3605         // return;
3606         // }
3607         // token = TokenNameSTRING;
3608         // continue;
3609         // case '"':
3610         // if (token == TokenNameEncapsedString2) {
3611         // return;
3612         // }
3613         // token = TokenNameSTRING;
3614         // continue;
3615         // }
3616         // }
3617         // return;
3618         // }
3619         // }
3620         // }
3621
3622         // private void encaps_var() {
3623         // // T_VARIABLE
3624         // // | T_VARIABLE '[' encaps_var_offset ']'
3625         // // | T_VARIABLE T_OBJECT_OPERATOR T_STRING
3626         // // | T_DOLLAR_OPEN_CURLY_BRACES expr '}'
3627         // // | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
3628         // // | T_CURLY_OPEN variable '}'
3629         // switch (token) {
3630         // case TokenNameVariable:
3631         // getNextToken();
3632         // if (token == TokenNameLBRACKET) {
3633         // getNextToken();
3634         // expr(); //encaps_var_offset();
3635         // if (token != TokenNameRBRACKET) {
3636         // throwSyntaxError("']' expected after variable.");
3637         // }
3638         // // scanner.encapsedStringStack.pop();
3639         // getNextToken();
3640         // // }
3641         // } else if (token == TokenNameMINUS_GREATER) {
3642         // getNextToken();
3643         // if (token != TokenNameIdentifier) {
3644         // throwSyntaxError("Identifier expected after '->'.");
3645         // }
3646         // // scanner.encapsedStringStack.pop();
3647         // getNextToken();
3648         // }
3649         // // else {
3650         // // // scanner.encapsedStringStack.pop();
3651         // // int tempToken = TokenNameSTRING;
3652         // // if (!scanner.encapsedStringStack.isEmpty()
3653         // // && (token == TokenNameEncapsedString0
3654         // // || token == TokenNameEncapsedString1
3655         // // || token == TokenNameEncapsedString2 || token ==
3656         // // TokenNameERROR)) {
3657         // // char encapsedChar = ((Character)
3658         // // scanner.encapsedStringStack.peek())
3659         // // .charValue();
3660         // // switch (token) {
3661         // // case TokenNameEncapsedString0 :
3662         // // if (encapsedChar == '`') {
3663         // // tempToken = TokenNameEncapsedString0;
3664         // // }
3665         // // break;
3666         // // case TokenNameEncapsedString1 :
3667         // // if (encapsedChar == '\'') {
3668         // // tempToken = TokenNameEncapsedString1;
3669         // // }
3670         // // break;
3671         // // case TokenNameEncapsedString2 :
3672         // // if (encapsedChar == '"') {
3673         // // tempToken = TokenNameEncapsedString2;
3674         // // }
3675         // // break;
3676         // // case TokenNameERROR :
3677         // // if (scanner.source[scanner.currentPosition - 1] == '\\') {
3678         // // scanner.currentPosition--;
3679         // // getNextToken();
3680         // // }
3681         // // break;
3682         // // }
3683         // // }
3684         // // token = tempToken;
3685         // // }
3686         // break;
3687         // case TokenNameDOLLAR_LBRACE:
3688         // getNextToken();
3689         // if (token == TokenNameDOLLAR_LBRACE) {
3690         // encaps_var();
3691         // } else if (token == TokenNameIdentifier) {
3692         // getNextToken();
3693         // if (token == TokenNameLBRACKET) {
3694         // getNextToken();
3695         // // if (token == TokenNameRBRACKET) {
3696         // // getNextToken();
3697         // // } else {
3698         // expr();
3699         // if (token != TokenNameRBRACKET) {
3700         // throwSyntaxError("']' expected after '${'.");
3701         // }
3702         // getNextToken();
3703         // // }
3704         // }
3705         // } else {
3706         // expr();
3707         // }
3708         // if (token != TokenNameRBRACE) {
3709         // throwSyntaxError("'}' expected.");
3710         // }
3711         // getNextToken();
3712         // break;
3713         // case TokenNameLBRACE_DOLLAR:
3714         // getNextToken();
3715         // if (token == TokenNameLBRACE_DOLLAR) {
3716         // encaps_var();
3717         // } else if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
3718         // getNextToken();
3719         // if (token == TokenNameLBRACKET) {
3720         // getNextToken();
3721         // // if (token == TokenNameRBRACKET) {
3722         // // getNextToken();
3723         // // } else {
3724         // expr();
3725         // if (token != TokenNameRBRACKET) {
3726         // throwSyntaxError("']' expected.");
3727         // }
3728         // getNextToken();
3729         // // }
3730         // } else if (token == TokenNameMINUS_GREATER) {
3731         // getNextToken();
3732         // if (token != TokenNameIdentifier && token != TokenNameVariable) {
3733         // throwSyntaxError("String or Variable token expected.");
3734         // }
3735         // getNextToken();
3736         // if (token == TokenNameLBRACKET) {
3737         // getNextToken();
3738         // // if (token == TokenNameRBRACKET) {
3739         // // getNextToken();
3740         // // } else {
3741         // expr();
3742         // if (token != TokenNameRBRACKET) {
3743         // throwSyntaxError("']' expected after '${'.");
3744         // }
3745         // getNextToken();
3746         // // }
3747         // }
3748         // }
3749         // // if (token != TokenNameRBRACE) {
3750         // // throwSyntaxError("'}' expected after '{$'.");
3751         // // }
3752         // // // scanner.encapsedStringStack.pop();
3753         // // getNextToken();
3754         // } else {
3755         // expr();
3756         // if (token != TokenNameRBRACE) {
3757         // throwSyntaxError("'}' expected.");
3758         // }
3759         // // scanner.encapsedStringStack.pop();
3760         // getNextToken();
3761         // }
3762         // break;
3763         // }
3764         // }
3765
3766         // private void encaps_var_offset() {
3767         // // T_STRING
3768         // // | T_NUM_STRING
3769         // // | T_VARIABLE
3770         // switch (token) {
3771         // case TokenNameSTRING:
3772         // getNextToken();
3773         // break;
3774         // case TokenNameIntegerLiteral:
3775         // getNextToken();
3776         // break;
3777         // case TokenNameVariable:
3778         // getNextToken();
3779         // break;
3780         // case TokenNameIdentifier:
3781         // getNextToken();
3782         // break;
3783         // default:
3784         // throwSyntaxError("Variable or String token expected.");
3785         // break;
3786         // }
3787         // }
3788
3789         private void internal_functions_in_yacc() {
3790                 // int start = 0;
3791                 switch (token) {
3792                 // case TokenNameisset:
3793                 // // T_ISSET '(' isset_variables ')'
3794                 // getNextToken();
3795                 // if (token != TokenNameLPAREN) {
3796                 // throwSyntaxError("'(' expected after keyword 'isset'");
3797                 // }
3798                 // getNextToken();
3799                 // isset_variables();
3800                 // if (token != TokenNameRPAREN) {
3801                 // throwSyntaxError("')' expected after keyword 'isset'");
3802                 // }
3803                 // getNextToken();
3804                 // break;
3805                 // case TokenNameempty:
3806                 // // T_EMPTY '(' variable ')'
3807                 // getNextToken();
3808                 // if (token != TokenNameLPAREN) {
3809                 // throwSyntaxError("'(' expected after keyword 'empty'");
3810                 // }
3811                 // getNextToken();
3812                 // variable(false);
3813                 // if (token != TokenNameRPAREN) {
3814                 // throwSyntaxError("')' expected after keyword 'empty'");
3815                 // }
3816                 // getNextToken();
3817                 // break;
3818                 case TokenNameinclude:
3819                         // T_INCLUDE expr
3820                         checkFileName(token);
3821                         break;
3822                 case TokenNameinclude_once:
3823                         // T_INCLUDE_ONCE expr
3824                         checkFileName(token);
3825                         break;
3826                 case TokenNameeval:
3827                         // T_EVAL '(' expr ')'
3828                         getNextToken();
3829                         if (token != TokenNameLPAREN) {
3830                                 throwSyntaxError("'(' expected after keyword 'eval'");
3831                         }
3832                         getNextToken();
3833                         expr();
3834                         if (token != TokenNameRPAREN) {
3835                                 throwSyntaxError("')' expected after keyword 'eval'");
3836                         }
3837                         getNextToken();
3838                         break;
3839                 case TokenNamerequire:
3840                         // T_REQUIRE expr
3841                         checkFileName(token);
3842                         break;
3843                 case TokenNamerequire_once:
3844                         // T_REQUIRE_ONCE expr
3845                         checkFileName(token);
3846                         break;
3847                 }
3848         }
3849
3850         /**
3851          * Parse and check the include file name
3852          *
3853          * @param includeToken
3854          */
3855         private void checkFileName(int includeToken) {
3856                 // <include-token> expr
3857                 int start = scanner.getCurrentTokenStartPosition();
3858                 boolean hasLPAREN = false;
3859                 getNextToken();
3860                 if (token == TokenNameLPAREN) {
3861                         hasLPAREN = true;
3862                         getNextToken();
3863                 }
3864                 Expression expression = expr();
3865                 if (hasLPAREN) {
3866                         if (token == TokenNameRPAREN) {
3867                                 getNextToken();
3868                         } else {
3869                                 throwSyntaxError("')' expected for keyword '" + scanner.toStringAction(includeToken) + "'");
3870                         }
3871                 }
3872                 char[] currTokenSource = scanner.getCurrentTokenSource(start);
3873                 IFile file = null;
3874                 if (scanner.compilationUnit != null) {
3875                         IResource resource = scanner.compilationUnit.getResource();
3876                         if (resource != null && resource instanceof IFile) {
3877                                 file = (IFile) resource;
3878                         }
3879                 }
3880                 char[][] tokens;
3881                 tokens = new char[1][];
3882                 tokens[0] = currTokenSource;
3883
3884                 ImportReference impt = new ImportReference(tokens, currTokenSource, start, scanner.getCurrentTokenEndPosition(), false);
3885                 impt.declarationSourceEnd = impt.sourceEnd;
3886                 impt.declarationEnd = impt.declarationSourceEnd;
3887                 // endPosition is just before the ;
3888                 impt.declarationSourceStart = start;
3889                 includesList.add(impt);
3890
3891                 if (expression instanceof StringLiteral) {
3892                         StringLiteral literal = (StringLiteral) expression;
3893                         char[] includeName = literal.source();
3894                         if (includeName.length == 0) {
3895                                 reportSyntaxError("Empty filename after keyword '" + scanner.toStringAction(includeToken) + "'", literal.sourceStart,
3896                                                 literal.sourceStart + 1);
3897                         }
3898                         String includeNameString = new String(includeName);
3899                         if (literal instanceof StringLiteralDQ) {
3900                                 if (includeNameString.indexOf('$') >= 0) {
3901                                         // assuming that the filename contains a variable => no filename check
3902                                         return;
3903                                 }
3904                         }
3905                         if (includeNameString.startsWith("http://")) {
3906                                 // assuming external include location
3907                                 return;
3908                         }
3909                         if (file != null) {
3910                                 // check the filename:
3911                                 // System.out.println(new String(compilationUnit.getFileName())+" - "+
3912                                 // expression.toStringExpression());
3913                                 IProject project = file.getProject();
3914                                 if (project != null) {
3915                                         IPath path = PHPFileUtil.determineFilePath(includeNameString, file, project);
3916
3917                                         if (path == null) {
3918                                                 // SyntaxError: "File: << >> doesn't exist in project."
3919                                                 String[] args = { expression.toStringExpression(), project.getLocation().toString() };
3920                                                 problemReporter.phpIncludeNotExistWarning(args, literal.sourceStart, literal.sourceEnd, referenceContext,
3921                                                                 compilationUnit.compilationResult);
3922                                         } else {
3923                                                 try {
3924                                                         String filePath = path.toString();
3925                                                         String ext = file.getRawLocation().getFileExtension();
3926                                                         int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
3927
3928                                                         IFile f = PHPFileUtil.createFile(path, project);
3929
3930                                                         impt.tokens = CharOperation.splitOn('/', filePath.toCharArray(), 0, filePath.length() - fileExtensionLength);
3931                                                         impt.setFile(f);
3932                                                 } catch (Exception e) {
3933                                                         // the file is outside of the workspace
3934                                                 }
3935                                         }
3936                                 }
3937                         }
3938                 }
3939         }
3940
3941         private void isset_variables() {
3942                 // variable
3943                 // | isset_variables ','
3944                 if (token == TokenNameRPAREN) {
3945                         throwSyntaxError("Variable expected after keyword 'isset'");
3946                 }
3947                 while (true) {
3948                         variable(true, false);
3949                         if (token == TokenNameCOMMA) {
3950                                 getNextToken();
3951                         } else {
3952                                 break;
3953                         }
3954                 }
3955         }
3956
3957         private boolean common_scalar() {
3958                 // common_scalar:
3959                 // T_LNUMBER
3960                 // | T_DNUMBER
3961                 // | T_CONSTANT_ENCAPSED_STRING
3962                 // | T_LINE
3963                 // | T_FILE
3964                 // | T_CLASS_C
3965                 // | T_METHOD_C
3966                 // | T_FUNC_C
3967                 switch (token) {
3968                 case TokenNameIntegerLiteral:
3969                         getNextToken();
3970                         return true;
3971                 case TokenNameDoubleLiteral:
3972                         getNextToken();
3973                         return true;
3974                 case TokenNameStringDoubleQuote:
3975                         getNextToken();
3976                         return true;
3977                 case TokenNameStringSingleQuote:
3978                         getNextToken();
3979                         return true;
3980                 case TokenNameStringInterpolated:
3981                         getNextToken();
3982                         return true;
3983                 case TokenNameFILE:
3984                         getNextToken();
3985                         return true;
3986                 case TokenNameLINE:
3987                         getNextToken();
3988                         return true;
3989                 case TokenNameCLASS_C:
3990                         getNextToken();
3991                         return true;
3992                 case TokenNameMETHOD_C:
3993                         getNextToken();
3994                         return true;
3995                 case TokenNameFUNC_C:
3996                         getNextToken();
3997                         return true;
3998                 }
3999                 return false;
4000         }
4001
4002         private void scalar() {
4003                 // scalar:
4004                 // T_STRING
4005                 // | T_STRING_VARNAME
4006                 // | class_constant
4007                 // | common_scalar
4008                 // | '"' encaps_list '"'
4009                 // | '\'' encaps_list '\''
4010                 // | T_START_HEREDOC encaps_list T_END_HEREDOC
4011                 throwSyntaxError("Not yet implemented (scalar).");
4012         }
4013
4014         private void static_scalar() {
4015                 // static_scalar: /* compile-time evaluated scalars */
4016                 // common_scalar
4017                 // | T_STRING
4018                 // | '+' static_scalar
4019                 // | '-' static_scalar
4020                 // | T_ARRAY '(' static_array_pair_list ')'
4021                 // | static_class_constant
4022                 if (common_scalar()) {
4023                         return;
4024                 }
4025                 switch (token) {
4026                 case TokenNameIdentifier:
4027                         getNextToken();
4028                         // static_class_constant:
4029                         // T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING
4030                         if (token == TokenNamePAAMAYIM_NEKUDOTAYIM) {
4031                                 getNextToken();
4032                                 if (token == TokenNameIdentifier) {
4033                                         getNextToken();
4034                                 } else {
4035                                         throwSyntaxError("Identifier expected after '::' operator.");
4036                                 }
4037                         }
4038                         break;
4039                 case TokenNameEncapsedString0:
4040                         try {
4041                                 scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4042                                 while (scanner.currentCharacter != '`') {
4043                                         if (scanner.currentCharacter == '\\') {
4044                                                 scanner.currentPosition++;
4045                                         }
4046                                         scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4047                                 }
4048                                 getNextToken();
4049                         } catch (IndexOutOfBoundsException e) {
4050                                 throwSyntaxError("'`' expected at end of static string.");
4051                         }
4052                         break;
4053                 // case TokenNameEncapsedString1:
4054                 // try {
4055                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4056                 // while (scanner.currentCharacter != '\'') {
4057                 // if (scanner.currentCharacter == '\\') {
4058                 // scanner.currentPosition++;
4059                 // }
4060                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4061                 // }
4062                 // getNextToken();
4063                 // } catch (IndexOutOfBoundsException e) {
4064                 // throwSyntaxError("'\'' expected at end of static string.");
4065                 // }
4066                 // break;
4067                 // case TokenNameEncapsedString2:
4068                 // try {
4069                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4070                 // while (scanner.currentCharacter != '"') {
4071                 // if (scanner.currentCharacter == '\\') {
4072                 // scanner.currentPosition++;
4073                 // }
4074                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4075                 // }
4076                 // getNextToken();
4077                 // } catch (IndexOutOfBoundsException e) {
4078                 // throwSyntaxError("'\"' expected at end of static string.");
4079                 // }
4080                 // break;
4081                 case TokenNameStringSingleQuote:
4082                         getNextToken();
4083                         break;
4084                 case TokenNameStringDoubleQuote:
4085                         getNextToken();
4086                         break;
4087                 case TokenNamePLUS:
4088                         getNextToken();
4089                         static_scalar();
4090                         break;
4091                 case TokenNameMINUS:
4092                         getNextToken();
4093                         static_scalar();
4094                         break;
4095                 case TokenNamearray:
4096                         getNextToken();
4097                         if (token != TokenNameLPAREN) {
4098                                 throwSyntaxError("'(' expected after keyword 'array'");
4099                         }
4100                         getNextToken();
4101                         if (token == TokenNameRPAREN) {
4102                                 getNextToken();
4103                                 break;
4104                         }
4105                         non_empty_static_array_pair_list();
4106                         if (token != TokenNameRPAREN) {
4107                                 throwSyntaxError("')' or ',' expected after keyword 'array'");
4108                         }
4109                         getNextToken();
4110                         break;
4111                 // case TokenNamenull :
4112                 // getNextToken();
4113                 // break;
4114                 // case TokenNamefalse :
4115                 // getNextToken();
4116                 // break;
4117                 // case TokenNametrue :
4118                 // getNextToken();
4119                 // break;
4120                 default:
4121                         throwSyntaxError("Static scalar/constant expected.");
4122                 }
4123         }
4124
4125         private void non_empty_static_array_pair_list() {
4126                 // non_empty_static_array_pair_list:
4127                 // non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW
4128                 // static_scalar
4129                 // | non_empty_static_array_pair_list ',' static_scalar
4130                 // | static_scalar T_DOUBLE_ARROW static_scalar
4131                 // | static_scalar
4132                 while (true) {
4133                         static_scalar();
4134                         if (token == TokenNameEQUAL_GREATER) {
4135                                 getNextToken();
4136                                 static_scalar();
4137                         }
4138                         if (token != TokenNameCOMMA) {
4139                                 break;
4140                         }
4141                         getNextToken();
4142                         if (token == TokenNameRPAREN) {
4143                                 break;
4144                         }
4145                 }
4146         }
4147
4148         // public void reportSyntaxError() { //int act, int currentKind, int
4149         // // stateStackTop) {
4150         // /* remember current scanner position */
4151         // int startPos = scanner.startPosition;
4152         // int currentPos = scanner.currentPosition;
4153         //
4154         // this.checkAndReportBracketAnomalies(problemReporter());
4155         // /* reset scanner where it was */
4156         // scanner.startPosition = startPos;
4157         // scanner.currentPosition = currentPos;
4158         // }
4159
4160         public static final int RoundBracket = 0;
4161
4162         public static final int SquareBracket = 1;
4163
4164         public static final int CurlyBracket = 2;
4165
4166         public static final int BracketKinds = 3;
4167
4168         protected int[] nestedMethod; // the ptr is nestedType
4169
4170         protected int nestedType, dimensions;
4171
4172         // variable set stack
4173         final static int VariableStackIncrement = 10;
4174
4175         HashMap fTypeVariables = null;
4176
4177         HashMap fMethodVariables = null;
4178
4179         ArrayList fStackUnassigned = new ArrayList();
4180
4181         // ast stack
4182         final static int AstStackIncrement = 100;
4183
4184         protected int astPtr;
4185
4186         protected ASTNode[] astStack = new ASTNode[AstStackIncrement];
4187
4188         protected int astLengthPtr;
4189
4190         protected int[] astLengthStack;
4191
4192         ASTNode[] noAstNodes = new ASTNode[AstStackIncrement];
4193
4194         public CompilationUnitDeclaration compilationUnit; /*
4195                                                                                                                                                                                                                          * the result from parse()
4196                                                                                                                                                                                                                          */
4197
4198         protected ReferenceContext referenceContext;
4199
4200         protected ProblemReporter problemReporter;
4201
4202         protected CompilerOptions options;
4203
4204         private ArrayList includesList;
4205
4206         // protected CompilationResult compilationResult;
4207         /**
4208          * Returns this parser's problem reporter initialized with its reference
4209          * context. Also it is assumed that a problem is going to be reported, so
4210          * initializes the compilation result's line positions.
4211          */
4212         public ProblemReporter problemReporter() {
4213                 if (scanner.recordLineSeparator) {
4214                         compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
4215                 }
4216                 problemReporter.referenceContext = referenceContext;
4217                 return problemReporter;
4218         }
4219
4220         /*
4221          * Reconsider the entire source looking for inconsistencies in {} () []
4222          */
4223         // public boolean checkAndReportBracketAnomalies(ProblemReporter
4224         // problemReporter) {
4225         // scanner.wasAcr = false;
4226         // boolean anomaliesDetected = false;
4227         // try {
4228         // char[] source = scanner.source;
4229         // int[] leftCount = { 0, 0, 0 };
4230         // int[] rightCount = { 0, 0, 0 };
4231         // int[] depths = { 0, 0, 0 };
4232         // int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10]
4233         // };
4234         // int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
4235         // int[][] rightPositions = new int[][] { new int[10], new int[10], new
4236         // int[10] };
4237         // int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10]
4238         // };
4239         // scanner.currentPosition = scanner.initialPosition; //starting
4240         // // point
4241         // // (first-zero-based
4242         // // char)
4243         // while (scanner.currentPosition < scanner.eofPosition) { //loop for
4244         // // jumping
4245         // // over
4246         // // comments
4247         // try {
4248         // // ---------Consume white space and handles
4249         // // startPosition---------
4250         // boolean isWhiteSpace;
4251         // do {
4252         // scanner.startPosition = scanner.currentPosition;
4253         // // if (((scanner.currentCharacter =
4254         // // source[scanner.currentPosition++]) == '\\') &&
4255         // // (source[scanner.currentPosition] == 'u')) {
4256         // // isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
4257         // // } else {
4258         // if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') ||
4259         // (scanner.currentCharacter == '\n'))) {
4260         // if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
4261         // // only record line positions we have not
4262         // // recorded yet
4263         // scanner.pushLineSeparator();
4264         // }
4265         // }
4266         // isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter);
4267         // // }
4268         // } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
4269         // // -------consume token until } is found---------
4270         // switch (scanner.currentCharacter) {
4271         // case '{': {
4272         // int index = leftCount[CurlyBracket]++;
4273         // if (index == leftPositions[CurlyBracket].length) {
4274         // System.arraycopy(leftPositions[CurlyBracket], 0,
4275         // (leftPositions[CurlyBracket] = new int[index * 2]), 0, index);
4276         // System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] =
4277         // new int[index * 2]), 0, index);
4278         // }
4279         // leftPositions[CurlyBracket][index] = scanner.startPosition;
4280         // leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
4281         // }
4282         // break;
4283         // case '}': {
4284         // int index = rightCount[CurlyBracket]++;
4285         // if (index == rightPositions[CurlyBracket].length) {
4286         // System.arraycopy(rightPositions[CurlyBracket], 0,
4287         // (rightPositions[CurlyBracket] = new int[index * 2]), 0, index);
4288         // System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] =
4289         // new int[index * 2]), 0, index);
4290         // }
4291         // rightPositions[CurlyBracket][index] = scanner.startPosition;
4292         // rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
4293         // }
4294         // break;
4295         // case '(': {
4296         // int index = leftCount[RoundBracket]++;
4297         // if (index == leftPositions[RoundBracket].length) {
4298         // System.arraycopy(leftPositions[RoundBracket], 0,
4299         // (leftPositions[RoundBracket] = new int[index * 2]), 0, index);
4300         // System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] =
4301         // new int[index * 2]), 0, index);
4302         // }
4303         // leftPositions[RoundBracket][index] = scanner.startPosition;
4304         // leftDepths[RoundBracket][index] = depths[RoundBracket]++;
4305         // }
4306         // break;
4307         // case ')': {
4308         // int index = rightCount[RoundBracket]++;
4309         // if (index == rightPositions[RoundBracket].length) {
4310         // System.arraycopy(rightPositions[RoundBracket], 0,
4311         // (rightPositions[RoundBracket] = new int[index * 2]), 0, index);
4312         // System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] =
4313         // new int[index * 2]), 0, index);
4314         // }
4315         // rightPositions[RoundBracket][index] = scanner.startPosition;
4316         // rightDepths[RoundBracket][index] = --depths[RoundBracket];
4317         // }
4318         // break;
4319         // case '[': {
4320         // int index = leftCount[SquareBracket]++;
4321         // if (index == leftPositions[SquareBracket].length) {
4322         // System.arraycopy(leftPositions[SquareBracket], 0,
4323         // (leftPositions[SquareBracket] = new int[index * 2]), 0, index);
4324         // System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] =
4325         // new int[index * 2]), 0, index);
4326         // }
4327         // leftPositions[SquareBracket][index] = scanner.startPosition;
4328         // leftDepths[SquareBracket][index] = depths[SquareBracket]++;
4329         // }
4330         // break;
4331         // case ']': {
4332         // int index = rightCount[SquareBracket]++;
4333         // if (index == rightPositions[SquareBracket].length) {
4334         // System.arraycopy(rightPositions[SquareBracket], 0,
4335         // (rightPositions[SquareBracket] = new int[index * 2]), 0, index);
4336         // System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket]
4337         // = new int[index * 2]), 0, index);
4338         // }
4339         // rightPositions[SquareBracket][index] = scanner.startPosition;
4340         // rightDepths[SquareBracket][index] = --depths[SquareBracket];
4341         // }
4342         // break;
4343         // case '\'': {
4344         // if (scanner.getNextChar('\\')) {
4345         // scanner.scanEscapeCharacter();
4346         // } else { // consume next character
4347         // scanner.unicodeAsBackSlash = false;
4348         // // if (((scanner.currentCharacter =
4349         // // source[scanner.currentPosition++]) ==
4350         // // '\\') &&
4351         // // (source[scanner.currentPosition] ==
4352         // // 'u')) {
4353         // // scanner.getNextUnicodeChar();
4354         // // } else {
4355         // if (scanner.withoutUnicodePtr != 0) {
4356         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4357         // scanner.currentCharacter;
4358         // }
4359         // // }
4360         // }
4361         // scanner.getNextChar('\'');
4362         // break;
4363         // }
4364         // case '"':
4365         // // consume next character
4366         // scanner.unicodeAsBackSlash = false;
4367         // // if (((scanner.currentCharacter =
4368         // // source[scanner.currentPosition++]) == '\\') &&
4369         // // (source[scanner.currentPosition] == 'u')) {
4370         // // scanner.getNextUnicodeChar();
4371         // // } else {
4372         // if (scanner.withoutUnicodePtr != 0) {
4373         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4374         // scanner.currentCharacter;
4375         // }
4376         // // }
4377         // while (scanner.currentCharacter != '"') {
4378         // if (scanner.currentCharacter == '\r') {
4379         // if (source[scanner.currentPosition] == '\n')
4380         // scanner.currentPosition++;
4381         // break; // the string cannot go further that
4382         // // the line
4383         // }
4384         // if (scanner.currentCharacter == '\n') {
4385         // break; // the string cannot go further that
4386         // // the line
4387         // }
4388         // if (scanner.currentCharacter == '\\') {
4389         // scanner.scanEscapeCharacter();
4390         // }
4391         // // consume next character
4392         // scanner.unicodeAsBackSlash = false;
4393         // // if (((scanner.currentCharacter =
4394         // // source[scanner.currentPosition++]) == '\\')
4395         // // && (source[scanner.currentPosition] == 'u'))
4396         // // {
4397         // // scanner.getNextUnicodeChar();
4398         // // } else {
4399         // if (scanner.withoutUnicodePtr != 0) {
4400         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4401         // scanner.currentCharacter;
4402         // }
4403         // // }
4404         // }
4405         // break;
4406         // case '/': {
4407         // int test;
4408         // if ((test = scanner.getNextChar('/', '*')) == 0) { //line
4409         // // comment
4410         // //get the next char
4411         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4412         // '\\')
4413         // && (source[scanner.currentPosition] == 'u')) {
4414         // //-------------unicode traitement
4415         // // ------------
4416         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4417         // scanner.currentPosition++;
4418         // while (source[scanner.currentPosition] == 'u') {
4419         // scanner.currentPosition++;
4420         // }
4421         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4422         // 15 || c1 < 0
4423         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4424         // || c2 < 0
4425         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4426         // || c3 < 0
4427         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4428         // || c4 < 0) { //error
4429         // // don't
4430         // // care of the
4431         // // value
4432         // scanner.currentCharacter = 'A';
4433         // } //something different from \n and \r
4434         // else {
4435         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4436         // }
4437         // }
4438         // while (scanner.currentCharacter != '\r' && scanner.currentCharacter !=
4439         // '\n') {
4440         // //get the next char
4441         // scanner.startPosition = scanner.currentPosition;
4442         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4443         // '\\')
4444         // && (source[scanner.currentPosition] == 'u')) {
4445         // //-------------unicode traitement
4446         // // ------------
4447         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4448         // scanner.currentPosition++;
4449         // while (source[scanner.currentPosition] == 'u') {
4450         // scanner.currentPosition++;
4451         // }
4452         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4453         // 15 || c1 < 0
4454         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4455         // || c2 < 0
4456         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4457         // || c3 < 0
4458         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4459         // || c4 < 0) { //error
4460         // // don't
4461         // // care of the
4462         // // value
4463         // scanner.currentCharacter = 'A';
4464         // } //something different from \n
4465         // // and \r
4466         // else {
4467         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4468         // }
4469         // }
4470         // }
4471         // if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') ||
4472         // (scanner.currentCharacter == '\n'))) {
4473         // if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
4474         // // only record line positions we
4475         // // have not recorded yet
4476         // scanner.pushLineSeparator();
4477         // if (this.scanner.taskTags != null) {
4478         // this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(),
4479         // this.scanner
4480         // .getCurrentTokenEndPosition());
4481         // }
4482         // }
4483         // }
4484         // break;
4485         // }
4486         // if (test > 0) { //traditional and annotation
4487         // // comment
4488         // boolean star = false;
4489         // // consume next character
4490         // scanner.unicodeAsBackSlash = false;
4491         // // if (((scanner.currentCharacter =
4492         // // source[scanner.currentPosition++]) ==
4493         // // '\\') &&
4494         // // (source[scanner.currentPosition] ==
4495         // // 'u')) {
4496         // // scanner.getNextUnicodeChar();
4497         // // } else {
4498         // if (scanner.withoutUnicodePtr != 0) {
4499         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4500         // scanner.currentCharacter;
4501         // }
4502         // // }
4503         // if (scanner.currentCharacter == '*') {
4504         // star = true;
4505         // }
4506         // //get the next char
4507         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4508         // '\\')
4509         // && (source[scanner.currentPosition] == 'u')) {
4510         // //-------------unicode traitement
4511         // // ------------
4512         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4513         // scanner.currentPosition++;
4514         // while (source[scanner.currentPosition] == 'u') {
4515         // scanner.currentPosition++;
4516         // }
4517         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4518         // 15 || c1 < 0
4519         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4520         // || c2 < 0
4521         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4522         // || c3 < 0
4523         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4524         // || c4 < 0) { //error
4525         // // don't
4526         // // care of the
4527         // // value
4528         // scanner.currentCharacter = 'A';
4529         // } //something different from * and /
4530         // else {
4531         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4532         // }
4533         // }
4534         // //loop until end of comment */
4535         // while ((scanner.currentCharacter != '/') || (!star)) {
4536         // star = scanner.currentCharacter == '*';
4537         // //get next char
4538         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4539         // '\\')
4540         // && (source[scanner.currentPosition] == 'u')) {
4541         // //-------------unicode traitement
4542         // // ------------
4543         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4544         // scanner.currentPosition++;
4545         // while (source[scanner.currentPosition] == 'u') {
4546         // scanner.currentPosition++;
4547         // }
4548         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4549         // 15 || c1 < 0
4550         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4551         // || c2 < 0
4552         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4553         // || c3 < 0
4554         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4555         // || c4 < 0) { //error
4556         // // don't
4557         // // care of the
4558         // // value
4559         // scanner.currentCharacter = 'A';
4560         // } //something different from * and
4561         // // /
4562         // else {
4563         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4564         // }
4565         // }
4566         // }
4567         // if (this.scanner.taskTags != null) {
4568         // this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(),
4569         // this.scanner.getCurrentTokenEndPosition());
4570         // }
4571         // break;
4572         // }
4573         // break;
4574         // }
4575         // default:
4576         // if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) {
4577         // scanner.scanIdentifierOrKeyword(false);
4578         // break;
4579         // }
4580         // if (Character.isDigit(scanner.currentCharacter)) {
4581         // scanner.scanNumber(false);
4582         // break;
4583         // }
4584         // }
4585         // //-----------------end switch while
4586         // // try--------------------
4587         // } catch (IndexOutOfBoundsException e) {
4588         // break; // read until EOF
4589         // } catch (InvalidInputException e) {
4590         // return false; // no clue
4591         // }
4592         // }
4593         // if (scanner.recordLineSeparator) {
4594         // compilationUnit.compilationResult.lineSeparatorPositions =
4595         // scanner.getLineEnds();
4596         // }
4597         // // check placement anomalies against other kinds of brackets
4598         // for (int kind = 0; kind < BracketKinds; kind++) {
4599         // for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
4600         // int start = leftPositions[kind][leftIndex]; // deepest
4601         // // first
4602         // // find matching closing bracket
4603         // int depth = leftDepths[kind][leftIndex];
4604         // int end = -1;
4605         // for (int i = 0; i < rightCount[kind]; i++) {
4606         // int pos = rightPositions[kind][i];
4607         // // want matching bracket further in source with same
4608         // // depth
4609         // if ((pos > start) && (depth == rightDepths[kind][i])) {
4610         // end = pos;
4611         // break;
4612         // }
4613         // }
4614         // if (end < 0) { // did not find a good closing match
4615         // problemReporter.unmatchedBracket(start, referenceContext,
4616         // compilationUnit.compilationResult);
4617         // return true;
4618         // }
4619         // // check if even number of opening/closing other brackets
4620         // // in between this pair of brackets
4621         // int balance = 0;
4622         // for (int otherKind = 0; (balance == 0) && (otherKind < BracketKinds);
4623         // otherKind++) {
4624         // for (int i = 0; i < leftCount[otherKind]; i++) {
4625         // int pos = leftPositions[otherKind][i];
4626         // if ((pos > start) && (pos < end))
4627         // balance++;
4628         // }
4629         // for (int i = 0; i < rightCount[otherKind]; i++) {
4630         // int pos = rightPositions[otherKind][i];
4631         // if ((pos > start) && (pos < end))
4632         // balance--;
4633         // }
4634         // if (balance != 0) {
4635         // problemReporter.unmatchedBracket(start, referenceContext,
4636         // compilationUnit.compilationResult); //bracket
4637         // // anomaly
4638         // return true;
4639         // }
4640         // }
4641         // }
4642         // // too many opening brackets ?
4643         // for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
4644         // anomaliesDetected = true;
4645         // problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i -
4646         // 1], referenceContext,
4647         // compilationUnit.compilationResult);
4648         // }
4649         // // too many closing brackets ?
4650         // for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
4651         // anomaliesDetected = true;
4652         // problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext,
4653         // compilationUnit.compilationResult);
4654         // }
4655         // if (anomaliesDetected)
4656         // return true;
4657         // }
4658         // return anomaliesDetected;
4659         // } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
4660         // return anomaliesDetected;
4661         // } catch (NullPointerException e) { // jdk1.2.2 jit bug
4662         // return anomaliesDetected;
4663         // }
4664         // }
4665         protected void pushOnAstLengthStack(int pos) {
4666                 try {
4667                         astLengthStack[++astLengthPtr] = pos;
4668                 } catch (IndexOutOfBoundsException e) {
4669                         int oldStackLength = astLengthStack.length;
4670                         int[] oldPos = astLengthStack;
4671                         astLengthStack = new int[oldStackLength + StackIncrement];
4672                         System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
4673                         astLengthStack[astLengthPtr] = pos;
4674                 }
4675         }
4676
4677         protected void pushOnAstStack(ASTNode node) {
4678                 /*
4679                  * add a new obj on top of the ast stack
4680                  */
4681                 try {
4682                         astStack[++astPtr] = node;
4683                 } catch (IndexOutOfBoundsException e) {
4684                         int oldStackLength = astStack.length;
4685                         ASTNode[] oldStack = astStack;
4686                         astStack = new ASTNode[oldStackLength + AstStackIncrement];
4687                         System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
4688                         astPtr = oldStackLength;
4689                         astStack[astPtr] = node;
4690                 }
4691                 try {
4692                         astLengthStack[++astLengthPtr] = 1;
4693                 } catch (IndexOutOfBoundsException e) {
4694                         int oldStackLength = astLengthStack.length;
4695                         int[] oldPos = astLengthStack;
4696                         astLengthStack = new int[oldStackLength + AstStackIncrement];
4697                         System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
4698                         astLengthStack[astLengthPtr] = 1;
4699                 }
4700         }
4701
4702         protected void resetModifiers() {
4703                 this.modifiers = AccDefault;
4704                 this.modifiersSourceStart = -1; // <-- see comment into
4705                 // modifiersFlag(int)
4706                 this.scanner.commentPtr = -1;
4707         }
4708
4709         protected void consumePackageDeclarationName(IFile file) {
4710                 // create a package name similar to java package names
4711                 String projectPath = ProjectPrefUtil.getDocumentRoot(file.getProject()).toString();
4712                 String filePath = file.getRawLocation().toString();
4713                 String ext = file.getRawLocation().getFileExtension();
4714                 int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
4715                 ImportReference impt;
4716                 char[][] tokens;
4717                 if (filePath.startsWith(projectPath)) {
4718                         tokens = CharOperation
4719                                         .splitOn('/', filePath.toCharArray(), projectPath.length() + 1, filePath.length() - fileExtensionLength);
4720                 } else {
4721                         String name = file.getName();
4722                         tokens = new char[1][];
4723                         tokens[0] = name.substring(0, name.length() - fileExtensionLength).toCharArray();
4724                 }
4725
4726                 this.compilationUnit.currentPackage = impt = new ImportReference(tokens, new char[0], 0, 0, true);
4727
4728                 impt.declarationSourceStart = 0;
4729                 impt.declarationSourceEnd = 0;
4730                 impt.declarationEnd = 0;
4731                 // endPosition is just before the ;
4732
4733         }
4734
4735         public final static String[] GLOBALS = { "$this", "$_COOKIE", "$_ENV", "$_FILES", "$_GET", "$GLOBALS", "$_POST", "$_REQUEST",
4736                         "$_SESSION", "$_SERVER" };
4737
4738         /**
4739          *
4740          */
4741         private void pushFunctionVariableSet() {
4742                 HashSet set = new HashSet();
4743                 if (fStackUnassigned.isEmpty()) {
4744                         for (int i = 0; i < GLOBALS.length; i++) {
4745                                 set.add(GLOBALS[i]);
4746                         }
4747                 }
4748                 fStackUnassigned.add(set);
4749         }
4750
4751         private void pushIfVariableSet() {
4752                 if (!fStackUnassigned.isEmpty()) {
4753                         HashSet set = new HashSet();
4754                         fStackUnassigned.add(set);
4755                 }
4756         }
4757
4758         private HashSet removeIfVariableSet() {
4759                 if (!fStackUnassigned.isEmpty()) {
4760                         return (HashSet) fStackUnassigned.remove(fStackUnassigned.size() - 1);
4761                 }
4762                 return null;
4763         }
4764
4765         /**
4766          * Returns the <i>set of assigned variables </i> returns null if no Set is
4767          * defined at the current scanner position
4768          */
4769         private HashSet peekVariableSet() {
4770                 if (!fStackUnassigned.isEmpty()) {
4771                         return (HashSet) fStackUnassigned.get(fStackUnassigned.size() - 1);
4772                 }
4773                 return null;
4774         }
4775
4776         /**
4777          * add the current identifier source to the <i>set of assigned variables </i>
4778          *
4779          * @param set
4780          */
4781         private void addVariableSet(HashSet set) {
4782                 if (set != null) {
4783                         set.add(new String(scanner.getCurrentTokenSource()));
4784                 }
4785         }
4786
4787         /**
4788          * add the current identifier source to the <i>set of assigned variables </i>
4789          *
4790          */
4791         private void addVariableSet() {
4792                 HashSet set = peekVariableSet();
4793                 if (set != null) {
4794                         set.add(new String(scanner.getCurrentTokenSource()));
4795                 }
4796         }
4797
4798         /**
4799          * add the current identifier source to the <i>set of assigned variables </i>
4800          *
4801          */
4802         private void addVariableSet(char[] token) {
4803                 HashSet set = peekVariableSet();
4804                 if (set != null) {
4805                         set.add(new String(token));
4806                 }
4807         }
4808
4809         /**
4810          * check if the current identifier source is in the <i>set of assigned
4811          * variables </i> Returns true, if no set is defined for the current scanner
4812          * position
4813          *
4814          */
4815         private boolean containsVariableSet() {
4816                 return containsVariableSet(scanner.getCurrentTokenSource());
4817         }
4818
4819         private boolean containsVariableSet(char[] token) {
4820
4821                 if (!fStackUnassigned.isEmpty()) {
4822                         HashSet set;
4823                         String str = new String(token);
4824                         for (int i = 0; i < fStackUnassigned.size(); i++) {
4825                                 set = (HashSet) fStackUnassigned.get(i);
4826                                 if (set.contains(str)) {
4827                                         return true;
4828                                 }
4829                         }
4830                         return false;
4831                 }
4832                 return true;
4833         }
4834 }