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