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