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