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