bugfix 1427544, http://sourceforge.net/tracker/?func=detail&atid=484801&aid=1427544...
[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 if (token == TokenNameIdentifier) {
2902                         identifier(true, true);
2903                 } else {
2904                         if (token == TokenNamelist) {
2905                                 getNextToken();
2906                                 if (token == TokenNameLPAREN) {
2907                                         getNextToken();
2908                                         assignment_list();
2909                                         if (token != TokenNameRPAREN) {
2910                                                 throwSyntaxError("')' expected after 'list' keyword.");
2911                                         }
2912                                         getNextToken();
2913                                 } else {
2914                                         throwSyntaxError("'(' expected after 'list' keyword.");
2915                                 }
2916                         }
2917                 }
2918         }
2919
2920         private void array_pair_list() {
2921                 // array_pair_list:
2922                 // /* empty */
2923                 // | non_empty_array_pair_list possible_comma
2924                 non_empty_array_pair_list();
2925                 if (token == TokenNameCOMMA) {
2926                         getNextToken();
2927                 }
2928         }
2929
2930         private void non_empty_array_pair_list() {
2931                 // non_empty_array_pair_list:
2932                 // non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr
2933                 // | non_empty_array_pair_list ',' expr
2934                 // | expr T_DOUBLE_ARROW expr
2935                 // | expr
2936                 // | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable
2937                 // | non_empty_array_pair_list ',' '&' w_variable
2938                 // | expr T_DOUBLE_ARROW '&' w_variable
2939                 // | '&' w_variable
2940                 while (true) {
2941                         if (token == TokenNameAND) {
2942                                 getNextToken();
2943                                 variable(true, false);
2944                         } else {
2945                                 expr();
2946                                 if (token == TokenNameAND) {
2947                                         getNextToken();
2948                                         variable(true, false);
2949                                 } else if (token == TokenNameEQUAL_GREATER) {
2950                                         getNextToken();
2951                                         if (token == TokenNameAND) {
2952                                                 getNextToken();
2953                                                 variable(true, false);
2954                                         } else {
2955                                                 expr();
2956                                         }
2957                                 }
2958                         }
2959                         if (token != TokenNameCOMMA) {
2960                                 return;
2961                         }
2962                         getNextToken();
2963                         if (token == TokenNameRPAREN) {
2964                                 return;
2965                         }
2966                 }
2967         }
2968
2969         // private void variableList() {
2970         // do {
2971         // variable();
2972         // if (token == TokenNameCOMMA) {
2973         // getNextToken();
2974         // } else {
2975         // break;
2976         // }
2977         // } while (true);
2978         // }
2979         private Expression variable_without_objects(boolean lefthandside, boolean ignoreVar) {
2980                 // variable_without_objects:
2981                 // reference_variable
2982                 // | simple_indirect_reference reference_variable
2983                 if (Scanner.TRACE) {
2984                         System.out.println("TRACE: variable_without_objects()");
2985                 }
2986                 while (token == TokenNameDOLLAR) {
2987                         getNextToken();
2988                 }
2989                 return reference_variable(lefthandside, ignoreVar);
2990         }
2991
2992         private Expression function_call(boolean lefthandside, boolean ignoreVar) {
2993                 // function_call:
2994                 // T_STRING '(' function_call_parameter_list ')'
2995                 // | class_constant '(' function_call_parameter_list ')'
2996                 // | static_member '(' function_call_parameter_list ')'
2997                 // | variable_without_objects '(' function_call_parameter_list ')'
2998                 char[] defineName = null;
2999                 char[] ident = null;
3000                 int startPos = 0;
3001                 int endPos = 0;
3002                 Expression ref = null;
3003                 if (Scanner.TRACE) {
3004                         System.out.println("TRACE: function_call()");
3005                 }
3006                 if (token == TokenNameIdentifier) {
3007                         ident = scanner.getCurrentIdentifierSource();
3008                         defineName = ident;
3009                         startPos = scanner.getCurrentTokenStartPosition();
3010                         endPos = scanner.getCurrentTokenEndPosition();
3011                         getNextToken();
3012                         switch (token) {
3013                         case TokenNamePAAMAYIM_NEKUDOTAYIM:
3014                                 // static member:
3015                                 defineName = null;
3016                                 getNextToken();
3017                                 if (token == TokenNameIdentifier) {
3018                                         // class _constant
3019                                         getNextToken();
3020                                 } else {
3021                                         // static member:
3022                                         variable_without_objects(true, false);
3023                                 }
3024                                 break;
3025                         }
3026                 } else {
3027                         ref = variable_without_objects(lefthandside, ignoreVar);
3028                 }
3029                 if (token != TokenNameLPAREN) {
3030                         if (defineName != null) {
3031                                 // does this identifier contain only uppercase characters?
3032                                 if (defineName.length == 3) {
3033                                         if (defineName[0] == 'd' && defineName[1] == 'i' && defineName[2] == 'e') {
3034                                                 defineName = null;
3035                                         }
3036                                 } else if (defineName.length == 4) {
3037                                         if (defineName[0] == 't' && defineName[1] == 'r' && defineName[2] == 'u' && defineName[3] == 'e') {
3038                                                 defineName = null;
3039                                         } else if (defineName[0] == 'n' && defineName[1] == 'u' && defineName[2] == 'l' && defineName[3] == 'l') {
3040                                                 defineName = null;
3041                                         }
3042                                 } else if (defineName.length == 5) {
3043                                         if (defineName[0] == 'f' && defineName[1] == 'a' && defineName[2] == 'l' && defineName[3] == 's' && defineName[4] == 'e') {
3044                                                 defineName = null;
3045                                         }
3046                                 }
3047                                 if (defineName != null) {
3048                                         for (int i = 0; i < defineName.length; i++) {
3049                                                 if (Character.isLowerCase(defineName[i])) {
3050                                                         problemReporter.phpUppercaseIdentifierWarning(startPos, endPos, referenceContext, compilationUnit.compilationResult);
3051                                                         break;
3052                                                 }
3053                                         }
3054                                 }
3055                         }
3056                 } else {
3057                         getNextToken();
3058                         if (token == TokenNameRPAREN) {
3059                                 getNextToken();
3060                                 return ref;
3061                         }
3062                         non_empty_function_call_parameter_list();
3063                         if (token != TokenNameRPAREN) {
3064                                 String functionName;
3065                                 if (ident == null) {
3066                                         functionName = new String(" ");
3067                                 } else {
3068                                         functionName = new String(ident);
3069                                 }
3070                                 throwSyntaxError("')' expected in function call (" + functionName + ").");
3071                         }
3072                         getNextToken();
3073                 }
3074                 return ref;
3075         }
3076
3077         private void non_empty_function_call_parameter_list() {
3078                 this.non_empty_function_call_parameter_list(null);
3079         }
3080
3081         // private void function_call_parameter_list() {
3082         // function_call_parameter_list:
3083         // non_empty_function_call_parameter_list { $$ = $1; }
3084         // | /* empty */
3085         // }
3086         private void non_empty_function_call_parameter_list(String functionName) {
3087                 // non_empty_function_call_parameter_list:
3088                 // expr_without_variable
3089                 // | variable
3090                 // | '&' w_variable
3091                 // | non_empty_function_call_parameter_list ',' expr_without_variable
3092                 // | non_empty_function_call_parameter_list ',' variable
3093                 // | non_empty_function_call_parameter_list ',' '&' w_variable
3094                 if (Scanner.TRACE) {
3095                         System.out.println("TRACE: non_empty_function_call_parameter_list()");
3096                 }
3097                 UninitializedVariableHandler initHandler = new UninitializedVariableHandler();
3098                 initHandler.setFunctionName(functionName);
3099                 while (true) {
3100                         initHandler.incrementArgumentCount();
3101                         if (token == TokenNameAND) {
3102                                 getNextToken();
3103                                 w_variable(true);
3104                         } else {
3105                                 // if (token == TokenNameIdentifier || token ==
3106                                 // TokenNameVariable
3107                                 // || token == TokenNameDOLLAR) {
3108                                 // variable();
3109                                 // } else {
3110                                 expr_without_variable(true, initHandler);
3111                                 // }
3112                         }
3113                         if (token != TokenNameCOMMA) {
3114                                 break;
3115                         }
3116                         getNextToken();
3117                 }
3118         }
3119
3120         private void fully_qualified_class_name() {
3121                 if (token == TokenNameIdentifier) {
3122                         getNextToken();
3123                 } else {
3124                         throwSyntaxError("Class name expected.");
3125                 }
3126         }
3127
3128         private void static_member() {
3129                 // static_member:
3130                 // fully_qualified_class_name T_PAAMAYIM_NEKUDOTAYIM
3131                 // variable_without_objects
3132                 if (Scanner.TRACE) {
3133                         System.out.println("TRACE: static_member()");
3134                 }
3135                 fully_qualified_class_name();
3136                 if (token != TokenNamePAAMAYIM_NEKUDOTAYIM) {
3137                         throwSyntaxError("'::' expected after class name (static_member).");
3138                 }
3139                 getNextToken();
3140                 variable_without_objects(false, false);
3141         }
3142
3143         private Expression base_variable_with_function_calls(boolean lefthandside, boolean ignoreVar) {
3144                 // base_variable_with_function_calls:
3145                 // base_variable
3146                 // | function_call
3147                 if (Scanner.TRACE) {
3148                         System.out.println("TRACE: base_variable_with_function_calls()");
3149                 }
3150                 return function_call(lefthandside, ignoreVar);
3151         }
3152
3153         private Expression base_variable(boolean lefthandside) {
3154                 // base_variable:
3155                 // reference_variable
3156                 // | simple_indirect_reference reference_variable
3157                 // | static_member
3158                 Expression ref = null;
3159                 if (Scanner.TRACE) {
3160                         System.out.println("TRACE: base_variable()");
3161                 }
3162                 if (token == TokenNameIdentifier) {
3163                         static_member();
3164                 } else {
3165                         while (token == TokenNameDOLLAR) {
3166                                 getNextToken();
3167                         }
3168                         reference_variable(lefthandside, false);
3169                 }
3170                 return ref;
3171         }
3172
3173         // private void simple_indirect_reference() {
3174         // // simple_indirect_reference:
3175         // // '$'
3176         // //| simple_indirect_reference '$'
3177         // }
3178         private Expression reference_variable(boolean lefthandside, boolean ignoreVar) {
3179                 // reference_variable:
3180                 // reference_variable '[' dim_offset ']'
3181                 // | reference_variable '{' expr '}'
3182                 // | compound_variable
3183                 Expression ref = null;
3184                 if (Scanner.TRACE) {
3185                         System.out.println("TRACE: reference_variable()");
3186                 }
3187                 ref = compound_variable(lefthandside, ignoreVar);
3188                 while (true) {
3189                         if (token == TokenNameLBRACE) {
3190                                 ref = null;
3191                                 getNextToken();
3192                                 expr();
3193                                 if (token != TokenNameRBRACE) {
3194                                         throwSyntaxError("'}' expected in reference variable.");
3195                                 }
3196                                 getNextToken();
3197                         } else if (token == TokenNameLBRACKET) {
3198                                 // To remove "ref = null;" here, is probably better than the patch
3199                                 // commented in #1368081 - axelcl
3200                                 getNextToken();
3201                                 if (token != TokenNameRBRACKET) {
3202                                         expr();
3203                                         // dim_offset();
3204                                         if (token != TokenNameRBRACKET) {
3205                                                 throwSyntaxError("']' expected in reference variable.");
3206                                         }
3207                                 }
3208                                 getNextToken();
3209                         } else {
3210                                 break;
3211                         }
3212                 }
3213                 return ref;
3214         }
3215
3216         private Expression compound_variable(boolean lefthandside, boolean ignoreVar) {
3217                 // compound_variable:
3218                 // T_VARIABLE
3219                 // | '$' '{' expr '}'
3220                 if (Scanner.TRACE) {
3221                         System.out.println("TRACE: compound_variable()");
3222                 }
3223                 if (token == TokenNameVariable) {
3224                         if (!lefthandside) {
3225                                 if (!containsVariableSet()) {
3226                                         // reportSyntaxError("The local variable " + new
3227                                         // String(scanner.getCurrentIdentifierSource())
3228                                         // + " may not have been initialized");
3229                                         problemReporter.uninitializedLocalVariable(new String(scanner.getCurrentIdentifierSource()), scanner
3230                                                         .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), referenceContext,
3231                                                         compilationUnit.compilationResult);
3232                                 }
3233                         } else {
3234                                 if (!ignoreVar) {
3235                                         addVariableSet();
3236                                 }
3237                         }
3238                         FieldReference ref = new FieldReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition());
3239                         getNextToken();
3240                         return ref;
3241                 } else {
3242                         // because of simple_indirect_reference
3243                         while (token == TokenNameDOLLAR) {
3244                                 getNextToken();
3245                         }
3246                         if (token != TokenNameLBRACE) {
3247                                 reportSyntaxError("'{' expected after compound variable token '$'.");
3248                                 return null;
3249                         }
3250                         getNextToken();
3251                         expr();
3252                         if (token != TokenNameRBRACE) {
3253                                 throwSyntaxError("'}' expected after compound variable token '$'.");
3254                         }
3255                         getNextToken();
3256                 }
3257                 return null;
3258         } // private void dim_offset() { // // dim_offset: // // /* empty */
3259
3260         // // | expr
3261         // expr();
3262         // }
3263         private void object_property() {
3264                 // object_property:
3265                 // object_dim_list
3266                 // | variable_without_objects
3267                 if (Scanner.TRACE) {
3268                         System.out.println("TRACE: object_property()");
3269                 }
3270                 if (token == TokenNameVariable || token == TokenNameDOLLAR) {
3271                         variable_without_objects(false, false);
3272                 } else {
3273                         object_dim_list();
3274                 }
3275         }
3276
3277         private void object_dim_list() {
3278                 // object_dim_list:
3279                 // object_dim_list '[' dim_offset ']'
3280                 // | object_dim_list '{' expr '}'
3281                 // | variable_name
3282                 if (Scanner.TRACE) {
3283                         System.out.println("TRACE: object_dim_list()");
3284                 }
3285                 variable_name();
3286                 while (true) {
3287                         if (token == TokenNameLBRACE) {
3288                                 getNextToken();
3289                                 expr();
3290                                 if (token != TokenNameRBRACE) {
3291                                         throwSyntaxError("'}' expected in object_dim_list.");
3292                                 }
3293                                 getNextToken();
3294                         } else if (token == TokenNameLBRACKET) {
3295                                 getNextToken();
3296                                 if (token == TokenNameRBRACKET) {
3297                                         getNextToken();
3298                                         continue;
3299                                 }
3300                                 expr();
3301                                 if (token != TokenNameRBRACKET) {
3302                                         throwSyntaxError("']' expected in object_dim_list.");
3303                                 }
3304                                 getNextToken();
3305                         } else {
3306                                 break;
3307                         }
3308                 }
3309         }
3310
3311         private void variable_name() {
3312                 // variable_name:
3313                 // T_STRING
3314                 // | '{' expr '}'
3315                 if (Scanner.TRACE) {
3316                         System.out.println("TRACE: variable_name()");
3317                 }
3318                 if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
3319                         if (token > TokenNameKEYWORD) {
3320                                 // TODO show a warning "Keyword used as variable" ?
3321                         }
3322                         getNextToken();
3323                 } else {
3324                         if (token != TokenNameLBRACE) {
3325                                 throwSyntaxError("'{' expected in variable name.");
3326                         }
3327                         getNextToken();
3328                         expr();
3329                         if (token != TokenNameRBRACE) {
3330                                 throwSyntaxError("'}' expected in variable name.");
3331                         }
3332                         getNextToken();
3333                 }
3334         }
3335
3336         private void r_variable() {
3337                 variable(false, false);
3338         }
3339
3340         private void w_variable(boolean lefthandside) {
3341                 variable(lefthandside, false);
3342         }
3343
3344         private void rw_variable() {
3345                 variable(false, false);
3346         }
3347
3348         private Expression variable(boolean lefthandside, boolean ignoreVar) {
3349                 // variable:
3350                 // base_variable_with_function_calls T_OBJECT_OPERATOR
3351                 // object_property method_or_not variable_properties
3352                 // | base_variable_with_function_calls
3353                 Expression ref = base_variable_with_function_calls(lefthandside, ignoreVar);
3354                 if (token == TokenNameMINUS_GREATER) {
3355                         ref = null;
3356                         getNextToken();
3357                         object_property();
3358                         method_or_not();
3359                         variable_properties();
3360                 }
3361                 return ref;
3362         }
3363
3364         private void variable_properties() {
3365                 // variable_properties:
3366                 // variable_properties variable_property
3367                 // | /* empty */
3368                 while (token == TokenNameMINUS_GREATER) {
3369                         variable_property();
3370                 }
3371         }
3372
3373         private void variable_property() {
3374                 // variable_property:
3375                 // T_OBJECT_OPERATOR object_property method_or_not
3376                 if (Scanner.TRACE) {
3377                         System.out.println("TRACE: variable_property()");
3378                 }
3379                 if (token == TokenNameMINUS_GREATER) {
3380                         getNextToken();
3381                         object_property();
3382                         method_or_not();
3383                 } else {
3384                         throwSyntaxError("'->' expected in variable_property.");
3385                 }
3386         }
3387
3388         private Expression identifier(boolean lefthandside, boolean ignoreVar) {
3389                 // variable:
3390                 // base_variable_with_function_calls T_OBJECT_OPERATOR
3391                 // object_property method_or_not variable_properties
3392                 // | base_variable_with_function_calls
3393
3394                 // Expression ref = function_call(lefthandside, ignoreVar);
3395
3396                 // function_call:
3397                 // T_STRING '(' function_call_parameter_list ')'
3398                 // | class_constant '(' function_call_parameter_list ')'
3399                 // | static_member '(' function_call_parameter_list ')'
3400                 // | variable_without_objects '(' function_call_parameter_list ')'
3401                 char[] defineName = null;
3402                 char[] ident = null;
3403                 int startPos = 0;
3404                 int endPos = 0;
3405                 Expression ref = null;
3406                 if (Scanner.TRACE) {
3407                         System.out.println("TRACE: function_call()");
3408                 }
3409                 if (token == TokenNameIdentifier) {
3410                         ident = scanner.getCurrentIdentifierSource();
3411                         defineName = ident;
3412                         startPos = scanner.getCurrentTokenStartPosition();
3413                         endPos = scanner.getCurrentTokenEndPosition();
3414                         getNextToken();
3415
3416                         if (token == TokenNameEQUAL || token == TokenNamePLUS_EQUAL || token == TokenNameMINUS_EQUAL
3417                                         || token == TokenNameMULTIPLY_EQUAL || token == TokenNameDIVIDE_EQUAL || token == TokenNameDOT_EQUAL
3418                                         || token == TokenNameREMAINDER_EQUAL || token == TokenNameAND_EQUAL || token == TokenNameOR_EQUAL
3419                                         || token == TokenNameXOR_EQUAL || token == TokenNameRIGHT_SHIFT_EQUAL || token == TokenNameLEFT_SHIFT_EQUAL) {
3420                                 String error = "Assignment operator '" + scanner.toStringAction(token) + "' not allowed after identifier '"
3421                                                 + new String(ident) + "' (use 'define(...)' to define constants).";
3422                                 reportSyntaxError(error);
3423                         }
3424
3425                         switch (token) {
3426                         case TokenNamePAAMAYIM_NEKUDOTAYIM:
3427                                 // static member:
3428                                 defineName = null;
3429                                 getNextToken();
3430                                 if (token == TokenNameIdentifier) {
3431                                         // class _constant
3432                                         getNextToken();
3433                                 } else {
3434                                         // static member:
3435                                         variable_without_objects(true, false);
3436                                 }
3437                                 break;
3438                         }
3439                 } else {
3440                         ref = variable_without_objects(lefthandside, ignoreVar);
3441                 }
3442                 if (token != TokenNameLPAREN) {
3443                         if (defineName != null) {
3444                                 // does this identifier contain only uppercase characters?
3445                                 if (defineName.length == 3) {
3446                                         if (defineName[0] == 'd' && defineName[1] == 'i' && defineName[2] == 'e') {
3447                                                 defineName = null;
3448                                         }
3449                                 } else if (defineName.length == 4) {
3450                                         if (defineName[0] == 't' && defineName[1] == 'r' && defineName[2] == 'u' && defineName[3] == 'e') {
3451                                                 defineName = null;
3452                                         } else if (defineName[0] == 'n' && defineName[1] == 'u' && defineName[2] == 'l' && defineName[3] == 'l') {
3453                                                 defineName = null;
3454                                         }
3455                                 } else if (defineName.length == 5) {
3456                                         if (defineName[0] == 'f' && defineName[1] == 'a' && defineName[2] == 'l' && defineName[3] == 's' && defineName[4] == 'e') {
3457                                                 defineName = null;
3458                                         }
3459                                 }
3460                                 if (defineName != null) {
3461                                         for (int i = 0; i < defineName.length; i++) {
3462                                                 if (Character.isLowerCase(defineName[i])) {
3463                                                         problemReporter.phpUppercaseIdentifierWarning(startPos, endPos, referenceContext, compilationUnit.compilationResult);
3464                                                         break;
3465                                                 }
3466                                         }
3467                                 }
3468                         }
3469                         // TODO is this ok ?
3470                         // return ref;
3471                         // throwSyntaxError("'(' expected in function call.");
3472                 } else {
3473                         getNextToken();
3474
3475                         if (token == TokenNameRPAREN) {
3476                                 getNextToken();
3477                                 ref = null;
3478                         } else {
3479                                 String functionName;
3480                                 if (ident == null) {
3481                                         functionName = new String(" ");
3482                                 } else {
3483                                         functionName = new String(ident);
3484                                 }
3485                                 non_empty_function_call_parameter_list(functionName);
3486                                 if (token != TokenNameRPAREN) {
3487                                         throwSyntaxError("')' expected in function call (" + functionName + ").");
3488                                 }
3489                                 getNextToken();
3490                         }
3491                 }
3492                 if (token == TokenNameMINUS_GREATER) {
3493                         ref = null;
3494                         getNextToken();
3495                         object_property();
3496                         method_or_not();
3497                         variable_properties();
3498                 }
3499                 return ref;
3500         }
3501
3502         private void method_or_not() {
3503                 // method_or_not:
3504                 // '(' function_call_parameter_list ')'
3505                 // | /* empty */
3506                 if (Scanner.TRACE) {
3507                         System.out.println("TRACE: method_or_not()");
3508                 }
3509                 if (token == TokenNameLPAREN) {
3510                         getNextToken();
3511                         if (token == TokenNameRPAREN) {
3512                                 getNextToken();
3513                                 return;
3514                         }
3515                         non_empty_function_call_parameter_list();
3516                         if (token != TokenNameRPAREN) {
3517                                 throwSyntaxError("')' expected in method_or_not.");
3518                         }
3519                         getNextToken();
3520                 }
3521         }
3522
3523         private void exit_expr() {
3524                 // /* empty */
3525                 // | '(' ')'
3526                 // | '(' expr ')'
3527                 if (token != TokenNameLPAREN) {
3528                         return;
3529                 }
3530                 getNextToken();
3531                 if (token == TokenNameRPAREN) {
3532                         getNextToken();
3533                         return;
3534                 }
3535                 expr();
3536                 if (token != TokenNameRPAREN) {
3537                         throwSyntaxError("')' expected after keyword 'exit'");
3538                 }
3539                 getNextToken();
3540         }
3541
3542         // private void encaps_list() {
3543         // // encaps_list encaps_var
3544         // // | encaps_list T_STRING
3545         // // | encaps_list T_NUM_STRING
3546         // // | encaps_list T_ENCAPSED_AND_WHITESPACE
3547         // // | encaps_list T_CHARACTER
3548         // // | encaps_list T_BAD_CHARACTER
3549         // // | encaps_list '['
3550         // // | encaps_list ']'
3551         // // | encaps_list '{'
3552         // // | encaps_list '}'
3553         // // | encaps_list T_OBJECT_OPERATOR
3554         // // | /* empty */
3555         // while (true) {
3556         // switch (token) {
3557         // case TokenNameSTRING:
3558         // getNextToken();
3559         // break;
3560         // case TokenNameLBRACE:
3561         // // scanner.encapsedStringStack.pop();
3562         // getNextToken();
3563         // break;
3564         // case TokenNameRBRACE:
3565         // // scanner.encapsedStringStack.pop();
3566         // getNextToken();
3567         // break;
3568         // case TokenNameLBRACKET:
3569         // // scanner.encapsedStringStack.pop();
3570         // getNextToken();
3571         // break;
3572         // case TokenNameRBRACKET:
3573         // // scanner.encapsedStringStack.pop();
3574         // getNextToken();
3575         // break;
3576         // case TokenNameMINUS_GREATER:
3577         // // scanner.encapsedStringStack.pop();
3578         // getNextToken();
3579         // break;
3580         // case TokenNameVariable:
3581         // case TokenNameDOLLAR_LBRACE:
3582         // case TokenNameLBRACE_DOLLAR:
3583         // encaps_var();
3584         // break;
3585         // default:
3586         // char encapsedChar = ((Character)
3587         // scanner.encapsedStringStack.peek()).charValue();
3588         // if (encapsedChar == '$') {
3589         // scanner.encapsedStringStack.pop();
3590         // encapsedChar = ((Character)
3591         // scanner.encapsedStringStack.peek()).charValue();
3592         // switch (encapsedChar) {
3593         // case '`':
3594         // if (token == TokenNameEncapsedString0) {
3595         // return;
3596         // }
3597         // token = TokenNameSTRING;
3598         // continue;
3599         // case '\'':
3600         // if (token == TokenNameEncapsedString1) {
3601         // return;
3602         // }
3603         // token = TokenNameSTRING;
3604         // continue;
3605         // case '"':
3606         // if (token == TokenNameEncapsedString2) {
3607         // return;
3608         // }
3609         // token = TokenNameSTRING;
3610         // continue;
3611         // }
3612         // }
3613         // return;
3614         // }
3615         // }
3616         // }
3617
3618         // private void encaps_var() {
3619         // // T_VARIABLE
3620         // // | T_VARIABLE '[' encaps_var_offset ']'
3621         // // | T_VARIABLE T_OBJECT_OPERATOR T_STRING
3622         // // | T_DOLLAR_OPEN_CURLY_BRACES expr '}'
3623         // // | T_DOLLAR_OPEN_CURLY_BRACES T_STRING_VARNAME '[' expr ']' '}'
3624         // // | T_CURLY_OPEN variable '}'
3625         // switch (token) {
3626         // case TokenNameVariable:
3627         // getNextToken();
3628         // if (token == TokenNameLBRACKET) {
3629         // getNextToken();
3630         // expr(); //encaps_var_offset();
3631         // if (token != TokenNameRBRACKET) {
3632         // throwSyntaxError("']' expected after variable.");
3633         // }
3634         // // scanner.encapsedStringStack.pop();
3635         // getNextToken();
3636         // // }
3637         // } else if (token == TokenNameMINUS_GREATER) {
3638         // getNextToken();
3639         // if (token != TokenNameIdentifier) {
3640         // throwSyntaxError("Identifier expected after '->'.");
3641         // }
3642         // // scanner.encapsedStringStack.pop();
3643         // getNextToken();
3644         // }
3645         // // else {
3646         // // // scanner.encapsedStringStack.pop();
3647         // // int tempToken = TokenNameSTRING;
3648         // // if (!scanner.encapsedStringStack.isEmpty()
3649         // // && (token == TokenNameEncapsedString0
3650         // // || token == TokenNameEncapsedString1
3651         // // || token == TokenNameEncapsedString2 || token ==
3652         // // TokenNameERROR)) {
3653         // // char encapsedChar = ((Character)
3654         // // scanner.encapsedStringStack.peek())
3655         // // .charValue();
3656         // // switch (token) {
3657         // // case TokenNameEncapsedString0 :
3658         // // if (encapsedChar == '`') {
3659         // // tempToken = TokenNameEncapsedString0;
3660         // // }
3661         // // break;
3662         // // case TokenNameEncapsedString1 :
3663         // // if (encapsedChar == '\'') {
3664         // // tempToken = TokenNameEncapsedString1;
3665         // // }
3666         // // break;
3667         // // case TokenNameEncapsedString2 :
3668         // // if (encapsedChar == '"') {
3669         // // tempToken = TokenNameEncapsedString2;
3670         // // }
3671         // // break;
3672         // // case TokenNameERROR :
3673         // // if (scanner.source[scanner.currentPosition - 1] == '\\') {
3674         // // scanner.currentPosition--;
3675         // // getNextToken();
3676         // // }
3677         // // break;
3678         // // }
3679         // // }
3680         // // token = tempToken;
3681         // // }
3682         // break;
3683         // case TokenNameDOLLAR_LBRACE:
3684         // getNextToken();
3685         // if (token == TokenNameDOLLAR_LBRACE) {
3686         // encaps_var();
3687         // } else if (token == TokenNameIdentifier) {
3688         // getNextToken();
3689         // if (token == TokenNameLBRACKET) {
3690         // getNextToken();
3691         // // if (token == TokenNameRBRACKET) {
3692         // // getNextToken();
3693         // // } else {
3694         // expr();
3695         // if (token != TokenNameRBRACKET) {
3696         // throwSyntaxError("']' expected after '${'.");
3697         // }
3698         // getNextToken();
3699         // // }
3700         // }
3701         // } else {
3702         // expr();
3703         // }
3704         // if (token != TokenNameRBRACE) {
3705         // throwSyntaxError("'}' expected.");
3706         // }
3707         // getNextToken();
3708         // break;
3709         // case TokenNameLBRACE_DOLLAR:
3710         // getNextToken();
3711         // if (token == TokenNameLBRACE_DOLLAR) {
3712         // encaps_var();
3713         // } else if (token == TokenNameIdentifier || token > TokenNameKEYWORD) {
3714         // getNextToken();
3715         // if (token == TokenNameLBRACKET) {
3716         // getNextToken();
3717         // // if (token == TokenNameRBRACKET) {
3718         // // getNextToken();
3719         // // } else {
3720         // expr();
3721         // if (token != TokenNameRBRACKET) {
3722         // throwSyntaxError("']' expected.");
3723         // }
3724         // getNextToken();
3725         // // }
3726         // } else if (token == TokenNameMINUS_GREATER) {
3727         // getNextToken();
3728         // if (token != TokenNameIdentifier && token != TokenNameVariable) {
3729         // throwSyntaxError("String or Variable token expected.");
3730         // }
3731         // getNextToken();
3732         // if (token == TokenNameLBRACKET) {
3733         // getNextToken();
3734         // // if (token == TokenNameRBRACKET) {
3735         // // getNextToken();
3736         // // } else {
3737         // expr();
3738         // if (token != TokenNameRBRACKET) {
3739         // throwSyntaxError("']' expected after '${'.");
3740         // }
3741         // getNextToken();
3742         // // }
3743         // }
3744         // }
3745         // // if (token != TokenNameRBRACE) {
3746         // // throwSyntaxError("'}' expected after '{$'.");
3747         // // }
3748         // // // scanner.encapsedStringStack.pop();
3749         // // getNextToken();
3750         // } else {
3751         // expr();
3752         // if (token != TokenNameRBRACE) {
3753         // throwSyntaxError("'}' expected.");
3754         // }
3755         // // scanner.encapsedStringStack.pop();
3756         // getNextToken();
3757         // }
3758         // break;
3759         // }
3760         // }
3761
3762         // private void encaps_var_offset() {
3763         // // T_STRING
3764         // // | T_NUM_STRING
3765         // // | T_VARIABLE
3766         // switch (token) {
3767         // case TokenNameSTRING:
3768         // getNextToken();
3769         // break;
3770         // case TokenNameIntegerLiteral:
3771         // getNextToken();
3772         // break;
3773         // case TokenNameVariable:
3774         // getNextToken();
3775         // break;
3776         // case TokenNameIdentifier:
3777         // getNextToken();
3778         // break;
3779         // default:
3780         // throwSyntaxError("Variable or String token expected.");
3781         // break;
3782         // }
3783         // }
3784
3785         private void internal_functions_in_yacc() {
3786                 // int start = 0;
3787                 switch (token) {
3788                 // case TokenNameisset:
3789                 // // T_ISSET '(' isset_variables ')'
3790                 // getNextToken();
3791                 // if (token != TokenNameLPAREN) {
3792                 // throwSyntaxError("'(' expected after keyword 'isset'");
3793                 // }
3794                 // getNextToken();
3795                 // isset_variables();
3796                 // if (token != TokenNameRPAREN) {
3797                 // throwSyntaxError("')' expected after keyword 'isset'");
3798                 // }
3799                 // getNextToken();
3800                 // break;
3801                 // case TokenNameempty:
3802                 // // T_EMPTY '(' variable ')'
3803                 // getNextToken();
3804                 // if (token != TokenNameLPAREN) {
3805                 // throwSyntaxError("'(' expected after keyword 'empty'");
3806                 // }
3807                 // getNextToken();
3808                 // variable(false);
3809                 // if (token != TokenNameRPAREN) {
3810                 // throwSyntaxError("')' expected after keyword 'empty'");
3811                 // }
3812                 // getNextToken();
3813                 // break;
3814                 case TokenNameinclude:
3815                         // T_INCLUDE expr
3816                         checkFileName(token);
3817                         break;
3818                 case TokenNameinclude_once:
3819                         // T_INCLUDE_ONCE expr
3820                         checkFileName(token);
3821                         break;
3822                 case TokenNameeval:
3823                         // T_EVAL '(' expr ')'
3824                         getNextToken();
3825                         if (token != TokenNameLPAREN) {
3826                                 throwSyntaxError("'(' expected after keyword 'eval'");
3827                         }
3828                         getNextToken();
3829                         expr();
3830                         if (token != TokenNameRPAREN) {
3831                                 throwSyntaxError("')' expected after keyword 'eval'");
3832                         }
3833                         getNextToken();
3834                         break;
3835                 case TokenNamerequire:
3836                         // T_REQUIRE expr
3837                         checkFileName(token);
3838                         break;
3839                 case TokenNamerequire_once:
3840                         // T_REQUIRE_ONCE expr
3841                         checkFileName(token);
3842                         break;
3843                 }
3844         }
3845
3846         /**
3847          * Parse and check the include file name
3848          *
3849          * @param includeToken
3850          */
3851         private void checkFileName(int includeToken) {
3852                 // <include-token> expr
3853                 int start = scanner.getCurrentTokenStartPosition();
3854                 boolean hasLPAREN = false;
3855                 getNextToken();
3856                 if (token == TokenNameLPAREN) {
3857                         hasLPAREN = true;
3858                         getNextToken();
3859                 }
3860                 Expression expression = expr();
3861                 if (hasLPAREN) {
3862                         if (token == TokenNameRPAREN) {
3863                                 getNextToken();
3864                         } else {
3865                                 throwSyntaxError("')' expected for keyword '" + scanner.toStringAction(includeToken) + "'");
3866                         }
3867                 }
3868                 char[] currTokenSource = scanner.getCurrentTokenSource(start);
3869                 IFile file = null;
3870                 if (scanner.compilationUnit != null) {
3871                         IResource resource = scanner.compilationUnit.getResource();
3872                         if (resource != null && resource instanceof IFile) {
3873                                 file = (IFile) resource;
3874                         }
3875                 }
3876                 char[][] tokens;
3877                 tokens = new char[1][];
3878                 tokens[0] = currTokenSource;
3879
3880                 ImportReference impt = new ImportReference(tokens, currTokenSource, start, scanner.getCurrentTokenEndPosition(), false);
3881                 impt.declarationSourceEnd = impt.sourceEnd;
3882                 impt.declarationEnd = impt.declarationSourceEnd;
3883                 // endPosition is just before the ;
3884                 impt.declarationSourceStart = start;
3885                 includesList.add(impt);
3886
3887                 if (expression instanceof StringLiteral) {
3888                         StringLiteral literal = (StringLiteral) expression;
3889                         char[] includeName = literal.source();
3890                         if (includeName.length == 0) {
3891                                 reportSyntaxError("Empty filename after keyword '" + scanner.toStringAction(includeToken) + "'", literal.sourceStart,
3892                                                 literal.sourceStart + 1);
3893                         }
3894                         String includeNameString = new String(includeName);
3895                         if (literal instanceof StringLiteralDQ) {
3896                                 if (includeNameString.indexOf('$') >= 0) {
3897                                         // assuming that the filename contains a variable => no filename check
3898                                         return;
3899                                 }
3900                         }
3901                         if (includeNameString.startsWith("http://")) {
3902                                 // assuming external include location
3903                                 return;
3904                         }
3905                         if (file != null) {
3906                                 // check the filename:
3907                                 // System.out.println(new String(compilationUnit.getFileName())+" - "+
3908                                 // expression.toStringExpression());
3909                                 IProject project = file.getProject();
3910                                 if (project != null) {
3911                                         IPath path = PHPFileUtil.determineFilePath(includeNameString, file, project);
3912
3913                                         if (path == null) {
3914                                                 // SyntaxError: "File: << >> doesn't exist in project."
3915                                                 String[] args = { expression.toStringExpression(), project.getLocation().toString() };
3916                                                 problemReporter.phpIncludeNotExistWarning(args, literal.sourceStart, literal.sourceEnd, referenceContext,
3917                                                                 compilationUnit.compilationResult);
3918                                         } else {
3919                                                 try {
3920                                                         String filePath = path.toString();
3921                                                         String ext = file.getRawLocation().getFileExtension();
3922                                                         int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
3923
3924                                                         IFile f = PHPFileUtil.createFile(path, project);
3925
3926                                                         impt.tokens = CharOperation.splitOn('/', filePath.toCharArray(), 0, filePath.length() - fileExtensionLength);
3927                                                         impt.setFile(f);
3928                                                 } catch (Exception e) {
3929                                                         // the file is outside of the workspace
3930                                                 }
3931                                         }
3932                                 }
3933                         }
3934                 }
3935         }
3936
3937         private void isset_variables() {
3938                 // variable
3939                 // | isset_variables ','
3940                 if (token == TokenNameRPAREN) {
3941                         throwSyntaxError("Variable expected after keyword 'isset'");
3942                 }
3943                 while (true) {
3944                         variable(true, false);
3945                         if (token == TokenNameCOMMA) {
3946                                 getNextToken();
3947                         } else {
3948                                 break;
3949                         }
3950                 }
3951         }
3952
3953         private boolean common_scalar() {
3954                 // common_scalar:
3955                 // T_LNUMBER
3956                 // | T_DNUMBER
3957                 // | T_CONSTANT_ENCAPSED_STRING
3958                 // | T_LINE
3959                 // | T_FILE
3960                 // | T_CLASS_C
3961                 // | T_METHOD_C
3962                 // | T_FUNC_C
3963                 switch (token) {
3964                 case TokenNameIntegerLiteral:
3965                         getNextToken();
3966                         return true;
3967                 case TokenNameDoubleLiteral:
3968                         getNextToken();
3969                         return true;
3970                 case TokenNameStringDoubleQuote:
3971                         getNextToken();
3972                         return true;
3973                 case TokenNameStringSingleQuote:
3974                         getNextToken();
3975                         return true;
3976                 case TokenNameStringInterpolated:
3977                         getNextToken();
3978                         return true;
3979                 case TokenNameFILE:
3980                         getNextToken();
3981                         return true;
3982                 case TokenNameLINE:
3983                         getNextToken();
3984                         return true;
3985                 case TokenNameCLASS_C:
3986                         getNextToken();
3987                         return true;
3988                 case TokenNameMETHOD_C:
3989                         getNextToken();
3990                         return true;
3991                 case TokenNameFUNC_C:
3992                         getNextToken();
3993                         return true;
3994                 }
3995                 return false;
3996         }
3997
3998         private void scalar() {
3999                 // scalar:
4000                 // T_STRING
4001                 // | T_STRING_VARNAME
4002                 // | class_constant
4003                 // | common_scalar
4004                 // | '"' encaps_list '"'
4005                 // | '\'' encaps_list '\''
4006                 // | T_START_HEREDOC encaps_list T_END_HEREDOC
4007                 throwSyntaxError("Not yet implemented (scalar).");
4008         }
4009
4010         private void static_scalar() {
4011                 // static_scalar: /* compile-time evaluated scalars */
4012                 // common_scalar
4013                 // | T_STRING
4014                 // | '+' static_scalar
4015                 // | '-' static_scalar
4016                 // | T_ARRAY '(' static_array_pair_list ')'
4017                 // | static_class_constant
4018                 if (common_scalar()) {
4019                         return;
4020                 }
4021                 switch (token) {
4022                 case TokenNameIdentifier:
4023                         getNextToken();
4024                         // static_class_constant:
4025                         // T_STRING T_PAAMAYIM_NEKUDOTAYIM T_STRING
4026                         if (token == TokenNamePAAMAYIM_NEKUDOTAYIM) {
4027                                 getNextToken();
4028                                 if (token == TokenNameIdentifier) {
4029                                         getNextToken();
4030                                 } else {
4031                                         throwSyntaxError("Identifier expected after '::' operator.");
4032                                 }
4033                         }
4034                         break;
4035                 case TokenNameEncapsedString0:
4036                         try {
4037                                 scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4038                                 while (scanner.currentCharacter != '`') {
4039                                         if (scanner.currentCharacter == '\\') {
4040                                                 scanner.currentPosition++;
4041                                         }
4042                                         scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4043                                 }
4044                                 getNextToken();
4045                         } catch (IndexOutOfBoundsException e) {
4046                                 throwSyntaxError("'`' expected at end of static string.");
4047                         }
4048                         break;
4049                 // case TokenNameEncapsedString1:
4050                 // try {
4051                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4052                 // while (scanner.currentCharacter != '\'') {
4053                 // if (scanner.currentCharacter == '\\') {
4054                 // scanner.currentPosition++;
4055                 // }
4056                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4057                 // }
4058                 // getNextToken();
4059                 // } catch (IndexOutOfBoundsException e) {
4060                 // throwSyntaxError("'\'' expected at end of static string.");
4061                 // }
4062                 // break;
4063                 // case TokenNameEncapsedString2:
4064                 // try {
4065                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4066                 // while (scanner.currentCharacter != '"') {
4067                 // if (scanner.currentCharacter == '\\') {
4068                 // scanner.currentPosition++;
4069                 // }
4070                 // scanner.currentCharacter = scanner.source[scanner.currentPosition++];
4071                 // }
4072                 // getNextToken();
4073                 // } catch (IndexOutOfBoundsException e) {
4074                 // throwSyntaxError("'\"' expected at end of static string.");
4075                 // }
4076                 // break;
4077                 case TokenNameStringSingleQuote:
4078                         getNextToken();
4079                         break;
4080                 case TokenNameStringDoubleQuote:
4081                         getNextToken();
4082                         break;
4083                 case TokenNamePLUS:
4084                         getNextToken();
4085                         static_scalar();
4086                         break;
4087                 case TokenNameMINUS:
4088                         getNextToken();
4089                         static_scalar();
4090                         break;
4091                 case TokenNamearray:
4092                         getNextToken();
4093                         if (token != TokenNameLPAREN) {
4094                                 throwSyntaxError("'(' expected after keyword 'array'");
4095                         }
4096                         getNextToken();
4097                         if (token == TokenNameRPAREN) {
4098                                 getNextToken();
4099                                 break;
4100                         }
4101                         non_empty_static_array_pair_list();
4102                         if (token != TokenNameRPAREN) {
4103                                 throwSyntaxError("')' or ',' expected after keyword 'array'");
4104                         }
4105                         getNextToken();
4106                         break;
4107                 // case TokenNamenull :
4108                 // getNextToken();
4109                 // break;
4110                 // case TokenNamefalse :
4111                 // getNextToken();
4112                 // break;
4113                 // case TokenNametrue :
4114                 // getNextToken();
4115                 // break;
4116                 default:
4117                         throwSyntaxError("Static scalar/constant expected.");
4118                 }
4119         }
4120
4121         private void non_empty_static_array_pair_list() {
4122                 // non_empty_static_array_pair_list:
4123                 // non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW
4124                 // static_scalar
4125                 // | non_empty_static_array_pair_list ',' static_scalar
4126                 // | static_scalar T_DOUBLE_ARROW static_scalar
4127                 // | static_scalar
4128                 while (true) {
4129                         static_scalar();
4130                         if (token == TokenNameEQUAL_GREATER) {
4131                                 getNextToken();
4132                                 static_scalar();
4133                         }
4134                         if (token != TokenNameCOMMA) {
4135                                 break;
4136                         }
4137                         getNextToken();
4138                         if (token == TokenNameRPAREN) {
4139                                 break;
4140                         }
4141                 }
4142         }
4143
4144         // public void reportSyntaxError() { //int act, int currentKind, int
4145         // // stateStackTop) {
4146         // /* remember current scanner position */
4147         // int startPos = scanner.startPosition;
4148         // int currentPos = scanner.currentPosition;
4149         //
4150         // this.checkAndReportBracketAnomalies(problemReporter());
4151         // /* reset scanner where it was */
4152         // scanner.startPosition = startPos;
4153         // scanner.currentPosition = currentPos;
4154         // }
4155
4156         public static final int RoundBracket = 0;
4157
4158         public static final int SquareBracket = 1;
4159
4160         public static final int CurlyBracket = 2;
4161
4162         public static final int BracketKinds = 3;
4163
4164         protected int[] nestedMethod; // the ptr is nestedType
4165
4166         protected int nestedType, dimensions;
4167
4168         // variable set stack
4169         final static int VariableStackIncrement = 10;
4170
4171         HashMap fTypeVariables = null;
4172
4173         HashMap fMethodVariables = null;
4174
4175         ArrayList fStackUnassigned = new ArrayList();
4176
4177         // ast stack
4178         final static int AstStackIncrement = 100;
4179
4180         protected int astPtr;
4181
4182         protected ASTNode[] astStack = new ASTNode[AstStackIncrement];
4183
4184         protected int astLengthPtr;
4185
4186         protected int[] astLengthStack;
4187
4188         ASTNode[] noAstNodes = new ASTNode[AstStackIncrement];
4189
4190         public CompilationUnitDeclaration compilationUnit; /*
4191                                                                                                                                                                                                                          * the result from parse()
4192                                                                                                                                                                                                                          */
4193
4194         protected ReferenceContext referenceContext;
4195
4196         protected ProblemReporter problemReporter;
4197
4198         protected CompilerOptions options;
4199
4200         private ArrayList includesList;
4201
4202         // protected CompilationResult compilationResult;
4203         /**
4204          * Returns this parser's problem reporter initialized with its reference
4205          * context. Also it is assumed that a problem is going to be reported, so
4206          * initializes the compilation result's line positions.
4207          */
4208         public ProblemReporter problemReporter() {
4209                 if (scanner.recordLineSeparator) {
4210                         compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
4211                 }
4212                 problemReporter.referenceContext = referenceContext;
4213                 return problemReporter;
4214         }
4215
4216         /*
4217          * Reconsider the entire source looking for inconsistencies in {} () []
4218          */
4219         // public boolean checkAndReportBracketAnomalies(ProblemReporter
4220         // problemReporter) {
4221         // scanner.wasAcr = false;
4222         // boolean anomaliesDetected = false;
4223         // try {
4224         // char[] source = scanner.source;
4225         // int[] leftCount = { 0, 0, 0 };
4226         // int[] rightCount = { 0, 0, 0 };
4227         // int[] depths = { 0, 0, 0 };
4228         // int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10]
4229         // };
4230         // int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
4231         // int[][] rightPositions = new int[][] { new int[10], new int[10], new
4232         // int[10] };
4233         // int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10]
4234         // };
4235         // scanner.currentPosition = scanner.initialPosition; //starting
4236         // // point
4237         // // (first-zero-based
4238         // // char)
4239         // while (scanner.currentPosition < scanner.eofPosition) { //loop for
4240         // // jumping
4241         // // over
4242         // // comments
4243         // try {
4244         // // ---------Consume white space and handles
4245         // // startPosition---------
4246         // boolean isWhiteSpace;
4247         // do {
4248         // scanner.startPosition = scanner.currentPosition;
4249         // // if (((scanner.currentCharacter =
4250         // // source[scanner.currentPosition++]) == '\\') &&
4251         // // (source[scanner.currentPosition] == 'u')) {
4252         // // isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
4253         // // } else {
4254         // if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') ||
4255         // (scanner.currentCharacter == '\n'))) {
4256         // if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
4257         // // only record line positions we have not
4258         // // recorded yet
4259         // scanner.pushLineSeparator();
4260         // }
4261         // }
4262         // isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter);
4263         // // }
4264         // } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
4265         // // -------consume token until } is found---------
4266         // switch (scanner.currentCharacter) {
4267         // case '{': {
4268         // int index = leftCount[CurlyBracket]++;
4269         // if (index == leftPositions[CurlyBracket].length) {
4270         // System.arraycopy(leftPositions[CurlyBracket], 0,
4271         // (leftPositions[CurlyBracket] = new int[index * 2]), 0, index);
4272         // System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] =
4273         // new int[index * 2]), 0, index);
4274         // }
4275         // leftPositions[CurlyBracket][index] = scanner.startPosition;
4276         // leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
4277         // }
4278         // break;
4279         // case '}': {
4280         // int index = rightCount[CurlyBracket]++;
4281         // if (index == rightPositions[CurlyBracket].length) {
4282         // System.arraycopy(rightPositions[CurlyBracket], 0,
4283         // (rightPositions[CurlyBracket] = new int[index * 2]), 0, index);
4284         // System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] =
4285         // new int[index * 2]), 0, index);
4286         // }
4287         // rightPositions[CurlyBracket][index] = scanner.startPosition;
4288         // rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
4289         // }
4290         // break;
4291         // case '(': {
4292         // int index = leftCount[RoundBracket]++;
4293         // if (index == leftPositions[RoundBracket].length) {
4294         // System.arraycopy(leftPositions[RoundBracket], 0,
4295         // (leftPositions[RoundBracket] = new int[index * 2]), 0, index);
4296         // System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] =
4297         // new int[index * 2]), 0, index);
4298         // }
4299         // leftPositions[RoundBracket][index] = scanner.startPosition;
4300         // leftDepths[RoundBracket][index] = depths[RoundBracket]++;
4301         // }
4302         // break;
4303         // case ')': {
4304         // int index = rightCount[RoundBracket]++;
4305         // if (index == rightPositions[RoundBracket].length) {
4306         // System.arraycopy(rightPositions[RoundBracket], 0,
4307         // (rightPositions[RoundBracket] = new int[index * 2]), 0, index);
4308         // System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] =
4309         // new int[index * 2]), 0, index);
4310         // }
4311         // rightPositions[RoundBracket][index] = scanner.startPosition;
4312         // rightDepths[RoundBracket][index] = --depths[RoundBracket];
4313         // }
4314         // break;
4315         // case '[': {
4316         // int index = leftCount[SquareBracket]++;
4317         // if (index == leftPositions[SquareBracket].length) {
4318         // System.arraycopy(leftPositions[SquareBracket], 0,
4319         // (leftPositions[SquareBracket] = new int[index * 2]), 0, index);
4320         // System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] =
4321         // new int[index * 2]), 0, index);
4322         // }
4323         // leftPositions[SquareBracket][index] = scanner.startPosition;
4324         // leftDepths[SquareBracket][index] = depths[SquareBracket]++;
4325         // }
4326         // break;
4327         // case ']': {
4328         // int index = rightCount[SquareBracket]++;
4329         // if (index == rightPositions[SquareBracket].length) {
4330         // System.arraycopy(rightPositions[SquareBracket], 0,
4331         // (rightPositions[SquareBracket] = new int[index * 2]), 0, index);
4332         // System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket]
4333         // = new int[index * 2]), 0, index);
4334         // }
4335         // rightPositions[SquareBracket][index] = scanner.startPosition;
4336         // rightDepths[SquareBracket][index] = --depths[SquareBracket];
4337         // }
4338         // break;
4339         // case '\'': {
4340         // if (scanner.getNextChar('\\')) {
4341         // scanner.scanEscapeCharacter();
4342         // } else { // consume next character
4343         // scanner.unicodeAsBackSlash = false;
4344         // // if (((scanner.currentCharacter =
4345         // // source[scanner.currentPosition++]) ==
4346         // // '\\') &&
4347         // // (source[scanner.currentPosition] ==
4348         // // 'u')) {
4349         // // scanner.getNextUnicodeChar();
4350         // // } else {
4351         // if (scanner.withoutUnicodePtr != 0) {
4352         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4353         // scanner.currentCharacter;
4354         // }
4355         // // }
4356         // }
4357         // scanner.getNextChar('\'');
4358         // break;
4359         // }
4360         // case '"':
4361         // // consume next character
4362         // scanner.unicodeAsBackSlash = false;
4363         // // if (((scanner.currentCharacter =
4364         // // source[scanner.currentPosition++]) == '\\') &&
4365         // // (source[scanner.currentPosition] == 'u')) {
4366         // // scanner.getNextUnicodeChar();
4367         // // } else {
4368         // if (scanner.withoutUnicodePtr != 0) {
4369         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4370         // scanner.currentCharacter;
4371         // }
4372         // // }
4373         // while (scanner.currentCharacter != '"') {
4374         // if (scanner.currentCharacter == '\r') {
4375         // if (source[scanner.currentPosition] == '\n')
4376         // scanner.currentPosition++;
4377         // break; // the string cannot go further that
4378         // // the line
4379         // }
4380         // if (scanner.currentCharacter == '\n') {
4381         // break; // the string cannot go further that
4382         // // the line
4383         // }
4384         // if (scanner.currentCharacter == '\\') {
4385         // scanner.scanEscapeCharacter();
4386         // }
4387         // // consume next character
4388         // scanner.unicodeAsBackSlash = false;
4389         // // if (((scanner.currentCharacter =
4390         // // source[scanner.currentPosition++]) == '\\')
4391         // // && (source[scanner.currentPosition] == 'u'))
4392         // // {
4393         // // scanner.getNextUnicodeChar();
4394         // // } else {
4395         // if (scanner.withoutUnicodePtr != 0) {
4396         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4397         // scanner.currentCharacter;
4398         // }
4399         // // }
4400         // }
4401         // break;
4402         // case '/': {
4403         // int test;
4404         // if ((test = scanner.getNextChar('/', '*')) == 0) { //line
4405         // // comment
4406         // //get the next char
4407         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4408         // '\\')
4409         // && (source[scanner.currentPosition] == 'u')) {
4410         // //-------------unicode traitement
4411         // // ------------
4412         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4413         // scanner.currentPosition++;
4414         // while (source[scanner.currentPosition] == 'u') {
4415         // scanner.currentPosition++;
4416         // }
4417         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4418         // 15 || c1 < 0
4419         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4420         // || c2 < 0
4421         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4422         // || c3 < 0
4423         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4424         // || c4 < 0) { //error
4425         // // don't
4426         // // care of the
4427         // // value
4428         // scanner.currentCharacter = 'A';
4429         // } //something different from \n and \r
4430         // else {
4431         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4432         // }
4433         // }
4434         // while (scanner.currentCharacter != '\r' && scanner.currentCharacter !=
4435         // '\n') {
4436         // //get the next char
4437         // scanner.startPosition = scanner.currentPosition;
4438         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4439         // '\\')
4440         // && (source[scanner.currentPosition] == 'u')) {
4441         // //-------------unicode traitement
4442         // // ------------
4443         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4444         // scanner.currentPosition++;
4445         // while (source[scanner.currentPosition] == 'u') {
4446         // scanner.currentPosition++;
4447         // }
4448         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4449         // 15 || c1 < 0
4450         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4451         // || c2 < 0
4452         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4453         // || c3 < 0
4454         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4455         // || c4 < 0) { //error
4456         // // don't
4457         // // care of the
4458         // // value
4459         // scanner.currentCharacter = 'A';
4460         // } //something different from \n
4461         // // and \r
4462         // else {
4463         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4464         // }
4465         // }
4466         // }
4467         // if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') ||
4468         // (scanner.currentCharacter == '\n'))) {
4469         // if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
4470         // // only record line positions we
4471         // // have not recorded yet
4472         // scanner.pushLineSeparator();
4473         // if (this.scanner.taskTags != null) {
4474         // this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(),
4475         // this.scanner
4476         // .getCurrentTokenEndPosition());
4477         // }
4478         // }
4479         // }
4480         // break;
4481         // }
4482         // if (test > 0) { //traditional and annotation
4483         // // comment
4484         // boolean star = false;
4485         // // consume next character
4486         // scanner.unicodeAsBackSlash = false;
4487         // // if (((scanner.currentCharacter =
4488         // // source[scanner.currentPosition++]) ==
4489         // // '\\') &&
4490         // // (source[scanner.currentPosition] ==
4491         // // 'u')) {
4492         // // scanner.getNextUnicodeChar();
4493         // // } else {
4494         // if (scanner.withoutUnicodePtr != 0) {
4495         // scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] =
4496         // scanner.currentCharacter;
4497         // }
4498         // // }
4499         // if (scanner.currentCharacter == '*') {
4500         // star = true;
4501         // }
4502         // //get the next char
4503         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4504         // '\\')
4505         // && (source[scanner.currentPosition] == 'u')) {
4506         // //-------------unicode traitement
4507         // // ------------
4508         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4509         // scanner.currentPosition++;
4510         // while (source[scanner.currentPosition] == 'u') {
4511         // scanner.currentPosition++;
4512         // }
4513         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4514         // 15 || c1 < 0
4515         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4516         // || c2 < 0
4517         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4518         // || c3 < 0
4519         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4520         // || c4 < 0) { //error
4521         // // don't
4522         // // care of the
4523         // // value
4524         // scanner.currentCharacter = 'A';
4525         // } //something different from * and /
4526         // else {
4527         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4528         // }
4529         // }
4530         // //loop until end of comment */
4531         // while ((scanner.currentCharacter != '/') || (!star)) {
4532         // star = scanner.currentCharacter == '*';
4533         // //get next char
4534         // if (((scanner.currentCharacter = source[scanner.currentPosition++]) ==
4535         // '\\')
4536         // && (source[scanner.currentPosition] == 'u')) {
4537         // //-------------unicode traitement
4538         // // ------------
4539         // int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
4540         // scanner.currentPosition++;
4541         // while (source[scanner.currentPosition] == 'u') {
4542         // scanner.currentPosition++;
4543         // }
4544         // if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) >
4545         // 15 || c1 < 0
4546         // || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4547         // || c2 < 0
4548         // || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4549         // || c3 < 0
4550         // || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
4551         // || c4 < 0) { //error
4552         // // don't
4553         // // care of the
4554         // // value
4555         // scanner.currentCharacter = 'A';
4556         // } //something different from * and
4557         // // /
4558         // else {
4559         // scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
4560         // }
4561         // }
4562         // }
4563         // if (this.scanner.taskTags != null) {
4564         // this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(),
4565         // this.scanner.getCurrentTokenEndPosition());
4566         // }
4567         // break;
4568         // }
4569         // break;
4570         // }
4571         // default:
4572         // if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) {
4573         // scanner.scanIdentifierOrKeyword(false);
4574         // break;
4575         // }
4576         // if (Character.isDigit(scanner.currentCharacter)) {
4577         // scanner.scanNumber(false);
4578         // break;
4579         // }
4580         // }
4581         // //-----------------end switch while
4582         // // try--------------------
4583         // } catch (IndexOutOfBoundsException e) {
4584         // break; // read until EOF
4585         // } catch (InvalidInputException e) {
4586         // return false; // no clue
4587         // }
4588         // }
4589         // if (scanner.recordLineSeparator) {
4590         // compilationUnit.compilationResult.lineSeparatorPositions =
4591         // scanner.getLineEnds();
4592         // }
4593         // // check placement anomalies against other kinds of brackets
4594         // for (int kind = 0; kind < BracketKinds; kind++) {
4595         // for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
4596         // int start = leftPositions[kind][leftIndex]; // deepest
4597         // // first
4598         // // find matching closing bracket
4599         // int depth = leftDepths[kind][leftIndex];
4600         // int end = -1;
4601         // for (int i = 0; i < rightCount[kind]; i++) {
4602         // int pos = rightPositions[kind][i];
4603         // // want matching bracket further in source with same
4604         // // depth
4605         // if ((pos > start) && (depth == rightDepths[kind][i])) {
4606         // end = pos;
4607         // break;
4608         // }
4609         // }
4610         // if (end < 0) { // did not find a good closing match
4611         // problemReporter.unmatchedBracket(start, referenceContext,
4612         // compilationUnit.compilationResult);
4613         // return true;
4614         // }
4615         // // check if even number of opening/closing other brackets
4616         // // in between this pair of brackets
4617         // int balance = 0;
4618         // for (int otherKind = 0; (balance == 0) && (otherKind < BracketKinds);
4619         // otherKind++) {
4620         // for (int i = 0; i < leftCount[otherKind]; i++) {
4621         // int pos = leftPositions[otherKind][i];
4622         // if ((pos > start) && (pos < end))
4623         // balance++;
4624         // }
4625         // for (int i = 0; i < rightCount[otherKind]; i++) {
4626         // int pos = rightPositions[otherKind][i];
4627         // if ((pos > start) && (pos < end))
4628         // balance--;
4629         // }
4630         // if (balance != 0) {
4631         // problemReporter.unmatchedBracket(start, referenceContext,
4632         // compilationUnit.compilationResult); //bracket
4633         // // anomaly
4634         // return true;
4635         // }
4636         // }
4637         // }
4638         // // too many opening brackets ?
4639         // for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
4640         // anomaliesDetected = true;
4641         // problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i -
4642         // 1], referenceContext,
4643         // compilationUnit.compilationResult);
4644         // }
4645         // // too many closing brackets ?
4646         // for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
4647         // anomaliesDetected = true;
4648         // problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext,
4649         // compilationUnit.compilationResult);
4650         // }
4651         // if (anomaliesDetected)
4652         // return true;
4653         // }
4654         // return anomaliesDetected;
4655         // } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
4656         // return anomaliesDetected;
4657         // } catch (NullPointerException e) { // jdk1.2.2 jit bug
4658         // return anomaliesDetected;
4659         // }
4660         // }
4661         protected void pushOnAstLengthStack(int pos) {
4662                 try {
4663                         astLengthStack[++astLengthPtr] = pos;
4664                 } catch (IndexOutOfBoundsException e) {
4665                         int oldStackLength = astLengthStack.length;
4666                         int[] oldPos = astLengthStack;
4667                         astLengthStack = new int[oldStackLength + StackIncrement];
4668                         System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
4669                         astLengthStack[astLengthPtr] = pos;
4670                 }
4671         }
4672
4673         protected void pushOnAstStack(ASTNode node) {
4674                 /*
4675                  * add a new obj on top of the ast stack
4676                  */
4677                 try {
4678                         astStack[++astPtr] = node;
4679                 } catch (IndexOutOfBoundsException e) {
4680                         int oldStackLength = astStack.length;
4681                         ASTNode[] oldStack = astStack;
4682                         astStack = new ASTNode[oldStackLength + AstStackIncrement];
4683                         System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
4684                         astPtr = oldStackLength;
4685                         astStack[astPtr] = node;
4686                 }
4687                 try {
4688                         astLengthStack[++astLengthPtr] = 1;
4689                 } catch (IndexOutOfBoundsException e) {
4690                         int oldStackLength = astLengthStack.length;
4691                         int[] oldPos = astLengthStack;
4692                         astLengthStack = new int[oldStackLength + AstStackIncrement];
4693                         System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
4694                         astLengthStack[astLengthPtr] = 1;
4695                 }
4696         }
4697
4698         protected void resetModifiers() {
4699                 this.modifiers = AccDefault;
4700                 this.modifiersSourceStart = -1; // <-- see comment into
4701                 // modifiersFlag(int)
4702                 this.scanner.commentPtr = -1;
4703         }
4704
4705         protected void consumePackageDeclarationName(IFile file) {
4706                 // create a package name similar to java package names
4707                 String projectPath = ProjectPrefUtil.getDocumentRoot(file.getProject()).toString();
4708                 String filePath = file.getRawLocation().toString();
4709                 String ext = file.getRawLocation().getFileExtension();
4710                 int fileExtensionLength = ext == null ? 0 : ext.length() + 1;
4711                 ImportReference impt;
4712                 char[][] tokens;
4713                 if (filePath.startsWith(projectPath)) {
4714                         tokens = CharOperation
4715                                         .splitOn('/', filePath.toCharArray(), projectPath.length() + 1, filePath.length() - fileExtensionLength);
4716                 } else {
4717                         String name = file.getName();
4718                         tokens = new char[1][];
4719                         tokens[0] = name.substring(0, name.length() - fileExtensionLength).toCharArray();
4720                 }
4721
4722                 this.compilationUnit.currentPackage = impt = new ImportReference(tokens, new char[0], 0, 0, true);
4723
4724                 impt.declarationSourceStart = 0;
4725                 impt.declarationSourceEnd = 0;
4726                 impt.declarationEnd = 0;
4727                 // endPosition is just before the ;
4728
4729         }
4730
4731         public final static String[] GLOBALS = { "$this", "$_COOKIE", "$_ENV", "$_FILES", "$_GET", "$GLOBALS", "$_POST", "$_REQUEST",
4732                         "$_SESSION", "$_SERVER" };
4733
4734         /**
4735          *
4736          */
4737         private void pushFunctionVariableSet() {
4738                 HashSet set = new HashSet();
4739                 if (fStackUnassigned.isEmpty()) {
4740                         for (int i = 0; i < GLOBALS.length; i++) {
4741                                 set.add(GLOBALS[i]);
4742                         }
4743                 }
4744                 fStackUnassigned.add(set);
4745         }
4746
4747         private void pushIfVariableSet() {
4748                 if (!fStackUnassigned.isEmpty()) {
4749                         HashSet set = new HashSet();
4750                         fStackUnassigned.add(set);
4751                 }
4752         }
4753
4754         private HashSet removeIfVariableSet() {
4755                 if (!fStackUnassigned.isEmpty()) {
4756                         return (HashSet) fStackUnassigned.remove(fStackUnassigned.size() - 1);
4757                 }
4758                 return null;
4759         }
4760
4761         /**
4762          * Returns the <i>set of assigned variables </i> returns null if no Set is
4763          * defined at the current scanner position
4764          */
4765         private HashSet peekVariableSet() {
4766                 if (!fStackUnassigned.isEmpty()) {
4767                         return (HashSet) fStackUnassigned.get(fStackUnassigned.size() - 1);
4768                 }
4769                 return null;
4770         }
4771
4772         /**
4773          * add the current identifier source to the <i>set of assigned variables </i>
4774          *
4775          * @param set
4776          */
4777         private void addVariableSet(HashSet set) {
4778                 if (set != null) {
4779                         set.add(new String(scanner.getCurrentTokenSource()));
4780                 }
4781         }
4782
4783         /**
4784          * add the current identifier source to the <i>set of assigned variables </i>
4785          *
4786          */
4787         private void addVariableSet() {
4788                 HashSet set = peekVariableSet();
4789                 if (set != null) {
4790                         set.add(new String(scanner.getCurrentTokenSource()));
4791                 }
4792         }
4793
4794         /**
4795          * add the current identifier source to the <i>set of assigned variables </i>
4796          *
4797          */
4798         private void addVariableSet(char[] token) {
4799                 HashSet set = peekVariableSet();
4800                 if (set != null) {
4801                         set.add(new String(token));
4802                 }
4803         }
4804
4805         /**
4806          * check if the current identifier source is in the <i>set of assigned
4807          * variables </i> Returns true, if no set is defined for the current scanner
4808          * position
4809          *
4810          */
4811         private boolean containsVariableSet() {
4812                 return containsVariableSet(scanner.getCurrentTokenSource());
4813         }
4814
4815         private boolean containsVariableSet(char[] token) {
4816
4817                 if (!fStackUnassigned.isEmpty()) {
4818                         HashSet set;
4819                         String str = new String(token);
4820                         for (int i = 0; i < fStackUnassigned.size(); i++) {
4821                                 set = (HashSet) fStackUnassigned.get(i);
4822                                 if (set.contains(str)) {
4823                                         return true;
4824                                 }
4825                         }
4826                         return false;
4827                 }
4828                 return true;
4829         }
4830 }