new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / parser / Parser.java
1 /**********************************************************************
2 Copyright (c) 2002 Klaus Hartlage - www.eclipseproject.de
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
7
8 Contributors:
9     Klaus Hartlage - www.eclipseproject.de
10 **********************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.parser;
12
13 import java.util.ArrayList;
14
15 import net.sourceforge.phpdt.core.compiler.CharOperation;
16 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
17 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
18 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
20 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
21 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
22 import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
23 import net.sourceforge.phpeclipse.internal.compiler.ast.AstNode;
24 import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration;
25 import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration;
26 import net.sourceforge.phpeclipse.internal.compiler.ast.SingleTypeReference;
27 import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
28 import net.sourceforge.phpeclipse.phpeditor.PHPString;
29
30 import org.eclipse.core.resources.IFile;
31 import org.eclipse.core.runtime.CoreException;
32 import org.eclipse.jface.preference.IPreferenceStore;
33
34 import test.PHPParserSuperclass;
35
36 public class Parser extends PHPParserSuperclass implements ITerminalSymbols, ParserBasicInformation {
37   //internal data for the automat 
38   protected final static int StackIncrement = 255;
39   protected int stateStackTop;
40   protected int[] stack = new int[StackIncrement];
41   public int firstToken; // handle for multiple parsing goals
42   public int lastAct; //handle for multiple parsing goals
43   protected RecoveredElement currentElement;
44
45   public static boolean VERBOSE_RECOVERY = false;
46   protected boolean diet = false; //tells the scanner to jump over some parts of the code/expressions like method bodies
47
48   //scanner token
49   public Scanner scanner;
50
51   private ArrayList phpList;
52
53   private int currentPHPString;
54   private boolean phpEnd;
55
56   // private static HashMap keywordMap = null;
57   private String str;
58
59   // current character
60   //  char ch;
61   // current token
62   int token;
63
64   // row counter for syntax errors:
65   //int rowCount;
66   // column counter for syntax errors:
67   //int columnCount;
68
69   //int chIndx;
70   //
71   //    // current identifier
72   //    String identifier;
73
74   Long longNumber;
75   Double doubleNumber;
76
77   private String stringValue;
78
79   /** Contains the current expression. */
80   // private StringBuffer expression;
81
82   private boolean phpMode;
83
84   //    final static int TokenNameEOF = 0;
85   //    final static int TokenNameERROR = 1;
86   //    final static int TokenNameHTML = 2;
87   //
88   //    final static int TokenNameREMAINDER = 30;
89   //    final static int TokenNameNOT = 31;
90   //    final static int TokenNameDOT = 32;
91   //    final static int TokenNameXOR = 33;
92   //    final static int TokenNameDIVIDE = 34;
93   //    final static int TokenNameMULTIPLY = 35;
94   //    final static int TokenNameMINUS = 36;
95   //    final static int TokenNamePLUS = 37;
96   //    final static int TokenNameEQUAL_EQUAL = 38;
97   //    final static int TokenNameNOT_EQUAL = 39;
98   //    final static int TokenNameGREATER = 40;
99   //    final static int TokenNameGREATER_EQUAL = 41;
100   //    final static int TokenNameLESS = 42;
101   //    final static int TokenNameLESS_EQUAL = 43;
102   //    final static int TokenNameAND_AND = 44;
103   //    final static int TokenNameOR_OR = 45;
104   //    // final static int TokenNameHASH = 46; 
105   //    final static int TokenNameCOLON = 47;
106   //    final static int TokenNameDOT_EQUAL = 48;
107   //
108   //    final static int TokenNameEQUAL = 49;
109   //    final static int TokenNameMINUS_GREATER = 50; // ->
110   //    final static int TokenNameFOREACH = 51;
111   //    final static int TokenNameAND = 52;
112   //    //final static int TokenNameDOLLARLISTOPEN = 53;
113   //    final static int TokenNameTWIDDLE = 54;
114   //    final static int TokenNameTWIDDLE_EQUAL = 55;
115   //    final static int TokenNameREMAINDER_EQUAL = 56;
116   //    final static int TokenNameXOR_EQUAL = 57;
117   //    final static int TokenNameRIGHT_SHIFT_EQUAL = 58;
118   //    final static int TokenNameLEFT_SHIFT_EQUAL = 59;
119   //    final static int TokenNameAND_EQUAL = 60;
120   //    final static int TokenNameOR_EQUAL = 61;
121   //    final static int TokenNameQUESTION = 62;
122   //    final static int TokenNameCOLON_COLON = 63;
123   //    final static int TokenNameAT = 63;
124   //    // final static int TokenNameHEREDOC = 64;
125   //
126   //    final static int TokenNameDOLLAROPEN = 127;
127   //    final static int TokenNameLPAREN = 128;
128   //    final static int TokenNameRPAREN = 129;
129   //    final static int TokenNameLBRACE = 130;
130   //    final static int TokenNameRBRACE = 131;
131   //    final static int TokenNameLBRACKET = 132;
132   //    final static int TokenNameRBRACKET = 133;
133   //    final static int TokenNameCOMMA = 134;
134   //
135   //    final static int TokenNameStringLiteral = 136;
136   //    final static int TokenNameIdentifier = 138;
137   //    // final static int TokenNameDIGIT = 139;
138   //    final static int TokenNameSEMICOLON = 140;
139   //    // final static int TokenNameSLOT = 141;
140   //    // final static int TokenNameSLOTSEQUENCE = 142;
141   //    final static int TokenNameMINUS_MINUS = 144;
142   //    final static int TokenNamePLUS_PLUS = 145;
143   //    final static int TokenNamePLUS_EQUAL = 146;
144   //    final static int TokenNameDIVIDE_EQUAL = 147;
145   //    final static int TokenNameMINUS_EQUAL = 148;
146   //    final static int TokenNameMULTIPLY_EQUAL = 149;
147   //    final static int TokenNameVariable = 150;
148   //    final static int TokenNameIntegerLiteral = 151;
149   //    final static int TokenNameDoubleLiteral = 152;
150   //    final static int TokenNameStringInterpolated = 153;
151   //    final static int TokenNameStringConstant = 154;
152   //
153   //    final static int TokenNameLEFT_SHIFT = 155;
154   //    final static int TokenNameRIGHT_SHIFT = 156;
155   //    final static int TokenNameEQUAL_EQUAL_EQUAL = 157;
156   //    final static int TokenNameNOT_EQUAL_EQUAL = 158;
157   //    final static int TokenNameOR = 159;
158   //  final static int TokenNameAT = 153; // @
159
160   protected Parser() {
161     this.currentPHPString = 0;
162     //          PHPParserSuperclass.fileToParse = fileToParse;
163     this.phpList = null;
164     this.str = "";
165     this.token = TokenNameEOF;
166     //    this.chIndx = 0;
167     //    this.rowCount = 1;
168     //    this.columnCount = 0;
169     this.phpEnd = false;
170     //   getNextToken();
171
172     this.initializeScanner();
173   }
174
175   public void setFileToParse(IFile fileToParse) {
176     this.currentPHPString = 0;
177     PHPParserSuperclass.fileToParse = fileToParse;
178     this.phpList = null;
179     this.str = "";
180     this.token = TokenNameEOF;
181     this.phpEnd = false;
182     this.initializeScanner();
183   }
184   /**
185    *  ClassDeclaration Constructor.
186    *
187    *@param  s
188    *@param  sess  Description of Parameter
189    *@see
190    */
191   public Parser(IFile fileToParse) {
192     //    if (keywordMap == null) {
193     //      keywordMap = new HashMap();
194     //      for (int i = 0; i < PHP_KEYWORS.length; i++) {
195     //        keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
196     //      }
197     //    }
198     this.currentPHPString = 0;
199     PHPParserSuperclass.fileToParse = fileToParse;
200     this.phpList = null;
201     this.str = "";
202     this.token = TokenNameEOF;
203     //    this.chIndx = 0;
204     //    this.rowCount = 1;
205     //    this.columnCount = 0;
206     this.phpEnd = false;
207     //   getNextToken();
208
209     this.initializeScanner();
210   }
211
212   public void initializeScanner() {
213     this.scanner = new Scanner(false, false, false, false);
214   }
215   /**
216    * Create marker for the parse error
217    */
218   private void setMarker(String message, int charStart, int charEnd, int errorLevel) throws CoreException {
219     setMarker(fileToParse, message, charStart, charEnd, errorLevel);
220   }
221
222   /**
223    * This method will throw the SyntaxError.
224    * It will add the good lines and columns to the Error
225    * @param error the error message
226    * @throws SyntaxError the error raised
227    */
228   private void throwSyntaxError(String error) {
229
230     //    if (str.length() < chIndx) {
231     //      chIndx--;
232     //    }
233     //    // read until end-of-line
234     //    int eol = chIndx;
235     //    while (str.length() > eol) {
236     //      ch = str.charAt(eol++);
237     //      if (ch == '\n') {
238     //        eol--;
239     //        break;
240     //      }
241     //    }
242     //    throw new SyntaxError(
243     //      rowCount,
244     //      chIndx - columnCount + 1,
245     //      str.substring(columnCount, eol),
246     //      error);
247     throw new SyntaxError(1, 1, "", error);
248   }
249
250   /**
251    * This method will throw the SyntaxError.
252    * It will add the good lines and columns to the Error
253    * @param error the error message
254    * @throws SyntaxError the error raised
255    */
256   private void throwSyntaxError(String error, int startRow) {
257     throw new SyntaxError(startRow, 0, " ", error);
258   }
259
260   private void reportSyntaxError(String error, int problemStartPosition, int problemEndPosition) {
261     problemReporter.phpParsingError(new String[] { error }, problemStartPosition, problemEndPosition, referenceContext, compilationUnit.compilationResult);
262     throw new SyntaxError(1, 0, " ", error);
263   }
264   /**
265    *  Method Declaration.
266    *
267    *@see
268    */
269   //  private void getChar() {
270   //    if (str.length() > chIndx) {
271   //      ch = str.charAt(chIndx++);
272   //
273   //      return;
274   //    }
275   //
276   //    chIndx = str.length() + 1;
277   //    ch = ' ';
278   //    //  token = TokenNameEOF;
279   //    phpEnd = true;
280   //  }
281
282   /**
283    * gets the next token from input
284    */
285   private void getNextToken() throws CoreException {
286     try {
287       token = scanner.getNextToken();
288       if (Scanner.DEBUG) {
289         int currentEndPosition = scanner.getCurrentTokenEndPosition();
290         int currentStartPosition = scanner.getCurrentTokenStartPosition();
291
292         System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
293         System.out.println(scanner.toStringAction(token));
294       }
295     } catch (InvalidInputException e) {
296       token = TokenNameERROR;
297     }
298     return;
299
300   }
301
302   /**
303    * Get a number.
304    * if it's a <code>double</code> the number will be stored in <code>doubleNumber</code> and the token will have the
305    * value {@link Parser#TokenNameDOUBLE_NUMBER}<br />
306    * if it's a <code>double</code> the number will be stored in <code>longNumber</code> and the token will have the
307    * value {@link Parser#TokenNameINT_NUMBER}
308    */
309   //  private void getNumber() {
310   //    StringBuffer inum = new StringBuffer();
311   //    char dFlag = ' ';
312   //    int numFormat = 10;
313   //
314   //    // save first digit
315   //    char firstCh = ch;
316   //    inum.append(ch);
317   //
318   //    getChar();
319   //    // determine number conversions:
320   //    if (firstCh == '0') {
321   //      switch (ch) {
322   //        case 'b' :
323   //          numFormat = 2;
324   //          getChar();
325   //          break;
326   //        case 'B' :
327   //          numFormat = 2;
328   //          getChar();
329   //          break;
330   //        case 'o' :
331   //          numFormat = 8;
332   //          getChar();
333   //          break;
334   //        case 'O' :
335   //          numFormat = 8;
336   //          getChar();
337   //          break;
338   //        case 'x' :
339   //          numFormat = 16;
340   //          getChar();
341   //          break;
342   //        case 'X' :
343   //          numFormat = 16;
344   //          getChar();
345   //          break;
346   //      }
347   //    }
348   //
349   //    if (numFormat == 16) {
350   //      while ((ch >= '0' && ch <= '9')
351   //        || (ch >= 'a' && ch <= 'f')
352   //        || (ch >= 'A' && ch <= 'F')) {
353   //        inum.append(ch);
354   //        getChar();
355   //      }
356   //    } else {
357   //      while ((ch >= '0' && ch <= '9')
358   //        || (ch == '.')
359   //        || (ch == 'E')
360   //        || (ch == 'e')) {
361   //        if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
362   //          if (ch == '.' && dFlag != ' ') {
363   //            break;
364   //          }
365   //          if ((dFlag == 'E') || (dFlag == 'e')) {
366   //            break;
367   //          }
368   //          dFlag = ch;
369   //          inum.append(ch);
370   //          getChar();
371   //          if ((ch == '-') || (ch == '+')) {
372   //            inum.append(ch);
373   //            getChar();
374   //          }
375   //        } else {
376   //          inum.append(ch);
377   //          getChar();
378   //        }
379   //      }
380   //    }
381   //    chIndx--;
382   //
383   //    try {
384   //      if (dFlag != ' ') {
385   //        doubleNumber = new Double(inum.toString());
386   //        token = TokenNameDoubleLiteral;
387   //        return;
388   //      } else {
389   //        longNumber = Long.valueOf(inum.toString(), numFormat);
390   //        token = TokenNameIntegerLiteral;
391   //        return;
392   //      }
393   //
394   //    } catch (Throwable e) {
395   //      throwSyntaxError("Number format error: " + inum.toString());
396   //    }
397   //  }
398   //
399   //  /**
400   //   * Get a String.
401   //   * @param openChar the opening char ('\'', '"', '`')
402   //   * @param typeString the type of string {@link #TokenNameSTRING_CONSTANT},{@link #TokenNameINTERPOLATED_STRING}
403   //   * @param errorMsg the error message in case of parse error in the string
404   //   */
405   //  private void getString(
406   //    final char openChar,
407   //    final int typeString,
408   //    final String errorMsg) {
409   //    StringBuffer sBuffer = new StringBuffer();
410   //    boolean openString = true;
411   //    int startRow = rowCount;
412   //    while (str.length() > chIndx) {
413   //      ch = str.charAt(chIndx++);
414   //      if (ch == '\\') {
415   //        sBuffer.append(ch);
416   //        if (str.length() > chIndx) {
417   //          ch = str.charAt(chIndx++);
418   //          sBuffer.append(ch);
419   //        }
420   //      } else if (ch == openChar) {
421   //        openString = false;
422   //        break;
423   //      } else if (ch == '\n') {
424   //        rowCount++;
425   //        columnCount = chIndx;
426   //      } else {
427   //        sBuffer.append(ch);
428   //      }
429   //    }
430   //    if (openString) {
431   //      if (typeString == TokenNameStringConstant) {
432   //        throwSyntaxError(errorMsg, startRow);
433   //      } else {
434   //        throwSyntaxError(errorMsg);
435   //      }
436   //    }
437   //    token = typeString;
438   //    stringValue = sBuffer.toString();
439   //  }
440
441   //    public void htmlParserTester(String input) {
442   //            int lineNumber = 1;
443   //            int startLineNumber = 1;
444   //            int startIndex = 0;
445   //            char ch;
446   //            char ch2;
447   //            boolean phpMode = false;
448   //            boolean phpFound = false;
449   //
450   //            phpList = new ArrayList();
451   //            currentPHPString = 0;
452   //
453   //            try {
454   //                    int i = 0;
455   //                    while (i < input.length()) {
456   //                            ch = input.charAt(i++);
457   //                            if (ch == '\n') {
458   //                                    lineNumber++;
459   //                            }
460   //                            if ((!phpMode) && ch == '<') {
461   //                                    ch2 = input.charAt(i++);
462   //                                    if (ch2 == '?') {
463   //                                            ch2 = input.charAt(i++);
464   //                                            if (Character.isWhitespace(ch2)) {
465   //                                                    // php start
466   //                                                    phpMode = true;
467   //                                                    phpFound = true;
468   //                                                    startIndex = i;
469   //                                                    startLineNumber = lineNumber;
470   //                                                    continue;
471   //                                            } else if (ch2 == 'p') {
472   //                                                    ch2 = input.charAt(i++);
473   //                                                    if (ch2 == 'h') {
474   //                                                            ch2 = input.charAt(i++);
475   //                                                            if (ch2 == 'p') {
476   //                                                                    phpMode = true;
477   //                                                                    phpFound = true;
478   //                                                                    startIndex = i;
479   //                                                                    startLineNumber = lineNumber;
480   //                                                                    continue;
481   //                                                            }
482   //                                                            i--;
483   //                                                    }
484   //                                                    i--;
485   //                                            } else if (ch2 == 'P') {
486   //                                                    ch2 = input.charAt(i++);
487   //                                                    if (ch2 == 'H') {
488   //                                                            ch2 = input.charAt(i++);
489   //                                                            if (ch2 == 'P') {
490   //                                                                    phpMode = true;
491   //                                                                    phpFound = true;
492   //                                                                    startIndex = i;
493   //                                                                    startLineNumber = lineNumber;
494   //                                                                    continue;
495   //                                                            }
496   //                                                            i--;
497   //                                                    }
498   //                                                    i--;
499   //                                            }
500   //                                            i--;
501   //                                    }
502   //                                    i--;
503   //                            }
504   //
505   //                            if (phpMode) {
506   //                                    if (ch == '/' && i < input.length()) {
507   //                                            ch2 = input.charAt(i++);
508   //                                            if (ch2 == '/') {
509   //                                                    while (i < input.length()) {
510   //                                                            ch = input.charAt(i++);
511   //                                                            if (ch == '?' && i < input.length()) {
512   //                                                                    ch2 = input.charAt(i++);
513   //                                                                    if (ch2 == '>') {
514   //                                                                            // php end
515   //                                                                            phpMode = false;
516   //                                                                            phpList.add(
517   //                                                                                    new PHPString(
518   //                                                                                            input.substring(
519   //                                                                                                    startIndex,
520   //                                                                                                    i - 2),
521   //                                                                                            startLineNumber));
522   //                                                                            continue;
523   //                                                                    }
524   //                                                                    i--;
525   //                                                            } else if (ch == '\n') {
526   //                                                                    lineNumber++;
527   //                                                                    break;
528   //                                                            }
529   //                                                    }
530   //                                                    continue;
531   //                                            } else if (ch2 == '*') {
532   //                                                    // multi-line comment
533   //                                                    while (i < input.length()) {
534   //                                                            ch = input.charAt(i++);
535   //                                                            if (ch == '\n') {
536   //                                                                    lineNumber++;
537   //                                                            } else if (ch == '*' && i < input.length()) {
538   //                                                                    ch2 = input.charAt(i++);
539   //                                                                    if (ch2 == '/') {
540   //                                                                            break;
541   //                                                                    }
542   //                                                                    i--;
543   //                                                            }
544   //                                                    }
545   //                                                    continue;
546   //                                            } else {
547   //                                                    i--;
548   //                                            }
549   //                                    } else if (ch == '#') {
550   //                                            while (i < input.length()) {
551   //                                                    ch = input.charAt(i++);
552   //                                                    if (ch == '?' && i < input.length()) {
553   //                                                            ch2 = input.charAt(i++);
554   //                                                            if (ch2 == '>') {
555   //                                                                    // php end
556   //                                                                    phpMode = false;
557   //                                                                    phpList.add(
558   //                                                                            new PHPString(
559   //                                                                                    input.substring(startIndex, i - 2),
560   //                                                                                    startLineNumber));
561   //                                                                    continue;
562   //                                                            }
563   //                                                            i--;
564   //                                                    } else if (ch == '\n') {
565   //                                                            lineNumber++;
566   //                                                            break;
567   //                                                    }
568   //                                            }
569   //                                            continue;
570   //                                    } else if (ch == '"') {
571   //                                            ch = ' ';
572   //                                            while (i < input.length()) {
573   //                                                    ch = input.charAt(i++);
574   //                                                    if (ch == '\n') {
575   //                                                            lineNumber++;
576   //                                                    } else if (
577   //                                                            ch == '\\' && i < input.length()) { // escape
578   //                                                            i++;
579   //                                                    } else if (ch == '"') {
580   //                                                            break;
581   //                                                    }
582   //                                            }
583   //                                            continue;
584   //                                    } else if (ch == '\'') {
585   //                                            ch = ' ';
586   //                                            while (i < input.length()) {
587   //                                                    ch = input.charAt(i++);
588   //                                                    if (ch == '\n') {
589   //                                                            lineNumber++;
590   //                                                    } else if (
591   //                                                            ch == '\\' && i < input.length()) { // escape
592   //                                                            i++;
593   //                                                    } else if (ch == '\'') {
594   //                                                            break;
595   //                                                    }
596   //                                            }
597   //                                            continue;
598   //                                    }
599   //
600   //                                    if (ch == '?' && i < input.length()) {
601   //                                            ch2 = input.charAt(i++);
602   //                                            if (ch2 == '>') {
603   //                                                    // php end
604   //                                                    phpMode = false;
605   //                                                    phpList.add(
606   //                                                            new PHPString(
607   //                                                                    input.substring(startIndex, i - 2),
608   //                                                                    startLineNumber));
609   //                                                    continue;
610   //                                            }
611   //                                            i--;
612   //                                    }
613   //                            }
614   //                    }
615   //
616   //                    if (!phpFound) {
617   //                            setMarker(
618   //                                    "No PHP source code found.",
619   //                                    lineNumber,
620   //                                    PHPParser.INFO);
621   //                    } else {
622   //                            if (phpMode) {
623   //                                    setMarker(
624   //                                            "Open PHP tag at end of file.",
625   //                                            lineNumber,
626   //                                            PHPParser.INFO);
627   //                                    phpList.add(
628   //                                            new PHPString(
629   //                                                    input.substring(startIndex, i - 2),
630   //                                                    startLineNumber));
631   //                            }
632   //                            //        for (int j=0;j<phpList.size();j++) {
633   //                            //          String temp = ((PHPString)phpList.get(j)).getPHPString();
634   //                            //          int startIndx = temp.length()-10;
635   //                            //          if (startIndx<0) {
636   //                            //            startIndx = 0;
637   //                            //          }
638   //                            //          System.out.println(temp.substring(startIndx)+"?>");
639   //                            //        }
640   //                            phpParserTester(null, 1);
641   //                            //        PHPString temp;
642   //                            //        for(int j=0;j<phpList.size();j++) {
643   //                            //          temp = (PHPString) phpList.get(j);
644   //                            //          parser.start(temp.getPHPString(), temp.getLineNumber());
645   //                            //        }
646   //                    }
647   //            } catch (CoreException e) {
648   //            }
649   //    }
650
651   public void phpParserTester(String s, int rowCount) throws CoreException {
652     this.str = s;
653     if (s == null) {
654       if (phpList.size() != 0) {
655         this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
656       }
657     }
658     this.token = TokenNameEOF;
659     //    this.chIndx = 0;
660     //    this.rowCount = rowCount;
661     //    this.columnCount = 0;
662     this.phpEnd = false;
663     this.phpMode = true;
664     scanner.setSource(s.toCharArray());
665     scanner.setPHPMode(true);
666     getNextToken();
667     do {
668       try {
669         if (token != TokenNameEOF && token != TokenNameERROR) {
670           statementList();
671         }
672         if (token != TokenNameEOF) {
673           if (token == TokenNameERROR) {
674             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
675           }
676           if (token == TokenNameRPAREN) {
677             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
678           }
679           if (token == TokenNameRBRACE) {
680             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
681           }
682           if (token == TokenNameRBRACKET) {
683             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
684           }
685
686           if (token == TokenNameLPAREN) {
687             throwSyntaxError("Read character '('; end-of-file not reached.");
688           }
689           if (token == TokenNameLBRACE) {
690             throwSyntaxError("Read character '{';  end-of-file not reached.");
691           }
692           if (token == TokenNameLBRACKET) {
693             throwSyntaxError("Read character '[';  end-of-file not reached.");
694           }
695
696           throwSyntaxError("End-of-file not reached.");
697         }
698         return;
699       } catch (SyntaxError err) {
700         if (s != null) {
701           throw err;
702         } else {
703           //   setMarker(err.getMessage(), err.getLine(), ERROR);
704           setMarker(err.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
705         }
706         // if an error occured,
707         // try to find keywords 'class' or 'function'
708         // to parse the rest of the string
709         while (token != TokenNameEOF && token != TokenNameERROR) {
710           if (token == TokenNameclass || token == TokenNamefunction) {
711             break;
712           }
713           getNextToken();
714         }
715         if (token == TokenNameEOF || token == TokenNameERROR) {
716           return;
717         }
718       }
719     }
720     while (true);
721   }
722   public void init(String s) {
723     this.str = s;
724     this.token = TokenNameEOF;
725     //    this.chIndx = 0;
726     //    this.rowCount = 1;
727     //    this.columnCount = 0;
728     this.phpEnd = false;
729     this.phpMode = false;
730     /* scanner initialization */
731     scanner.setSource(s.toCharArray());
732     scanner.setPHPMode(false);
733   }
734
735   protected void initialize() {
736     compilationUnit = null;
737     referenceContext = null;
738     this.str = "";
739     this.token = TokenNameEOF;
740     //    this.chIndx = 0;
741     //    this.rowCount = 1;
742     //    this.columnCount = 0;
743     this.phpEnd = false;
744     this.phpMode = false;
745     scanner.setPHPMode(false);
746   }
747   /**
748    * Parses a string with php tags
749    * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
750    */
751   public void parse(String s) throws CoreException {
752     init(s);
753     parse();
754   }
755
756   /**
757          * Parses a string with php tags
758          * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
759          */
760   protected void parse() throws CoreException {
761     getNextToken();
762     do {
763       try {
764         if (token != TokenNameEOF && token != TokenNameERROR) {
765           statementList();
766         }
767         if (token != TokenNameEOF) {
768           if (token == TokenNameERROR) {
769             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
770           }
771           if (token == TokenNameRPAREN) {
772             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
773           }
774           if (token == TokenNameRBRACE) {
775             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
776           }
777           if (token == TokenNameRBRACKET) {
778             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
779           }
780
781           if (token == TokenNameLPAREN) {
782             throwSyntaxError("Read character '('; end-of-file not reached.");
783           }
784           if (token == TokenNameLBRACE) {
785             throwSyntaxError("Read character '{';  end-of-file not reached.");
786           }
787           if (token == TokenNameLBRACKET) {
788             throwSyntaxError("Read character '[';  end-of-file not reached.");
789           }
790
791           throwSyntaxError("End-of-file not reached.");
792         }
793         return;
794       } catch (SyntaxError sytaxErr1) {
795         // setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
796         setMarker(sytaxErr1.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
797         try {
798           // if an error occured,
799           // try to find keywords 'class' or 'function'
800           // to parse the rest of the string
801           while (token != TokenNameEOF && token != TokenNameERROR) {
802             if (token == TokenNameclass || token == TokenNamefunction) {
803               break;
804             }
805             getNextToken();
806           }
807           if (token == TokenNameEOF || token == TokenNameERROR) {
808             return;
809           }
810         } catch (SyntaxError sytaxErr2) {
811           //    setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
812           setMarker(sytaxErr2.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
813           return;
814         }
815       }
816     }
817     while (true);
818   }
819
820   public PHPOutlineInfo parseInfo(Object parent, String s) {
821     PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
822     //    Stack stack = new Stack();
823     //    stack.push(outlineInfo.getDeclarations());
824
825     this.str = s;
826     this.token = TokenNameEOF;
827     //    this.chIndx = 0;
828     //    this.rowCount = 1;
829     //    this.columnCount = 0;
830     this.phpEnd = false;
831     this.phpMode = false;
832     scanner.setSource(s.toCharArray());
833     scanner.setPHPMode(false);
834
835     try {
836       getNextToken();
837       parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
838     } catch (CoreException e) {
839     }
840     return outlineInfo;
841   }
842
843   private boolean isVariable() {
844     return token == TokenNameVariable || token == TokenNamethis;
845   }
846
847   private void parseDeclarations(PHPOutlineInfo outlineInfo, OutlineableWithChildren current, boolean goBack) {
848     char[] ident;
849     //   PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
850     PHPSegmentWithChildren temp;
851     int counter = 0;
852
853     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
854     try {
855       while (token != TokenNameEOF && token != TokenNameERROR) {
856         if (token == TokenNameVariable) {
857           ident = scanner.getCurrentIdentifierSource();
858           outlineInfo.addVariable(new String(ident));
859           getNextToken();
860         } else if (token == TokenNamevar) {
861           getNextToken();
862           if (token == TokenNameVariable && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
863             ident = scanner.getCurrentIdentifierSource();
864             //substring(1) added because PHPVarDeclaration doesn't need the $ anymore
865             String variableName = new String(ident).substring(1);
866             outlineInfo.addVariable(variableName);
867             getNextToken();
868             if (token != TokenNameSEMICOLON) {
869
870               getNextToken();
871               ident = scanner.getCurrentTokenSource();
872               if (token > TokenNameKEYWORD) {
873                 current.add(new PHPVarDeclaration(current, variableName,
874                 //                      chIndx - ident.length,
875                 scanner.getCurrentTokenStartPosition(), new String(ident)));
876               } else {
877                 switch (token) {
878                   case TokenNameVariable :
879                   case TokenNamethis :
880                     current.add(new PHPVarDeclaration(current, variableName,
881                     //                      chIndx - ident.length,
882                     scanner.getCurrentTokenStartPosition(), new String(ident)));
883                     break;
884                   case TokenNameIdentifier :
885                     current.add(new PHPVarDeclaration(current, variableName,
886                     //                    chIndx - ident.length,
887                     scanner.getCurrentTokenStartPosition(), new String(ident)));
888                     break;
889                   case TokenNameDoubleLiteral :
890                     current.add(new PHPVarDeclaration(current, variableName + doubleNumber,
891                     //   chIndx - ident.length,
892                     scanner.getCurrentTokenStartPosition(), new String(ident)));
893                     break;
894                   case TokenNameIntegerLiteral :
895                     current.add(new PHPVarDeclaration(current, variableName,
896                     //                 chIndx - ident.length,
897                     scanner.getCurrentTokenStartPosition(), new String(ident)));
898                     break;
899                   case TokenNameStringInterpolated :
900                   case TokenNameStringLiteral :
901                     current.add(new PHPVarDeclaration(current, variableName,
902                     //              chIndx - ident.length,
903                     scanner.getCurrentTokenStartPosition(), new String(ident)));
904                     break;
905                   case TokenNameStringConstant :
906                     current.add(new PHPVarDeclaration(current, variableName,
907                     //   chIndx - ident.length,
908                     scanner.getCurrentTokenStartPosition(), new String(ident)));
909                     break;
910                   default :
911                     current.add(new PHPVarDeclaration(current, variableName,
912                     //               chIndx - ident.length
913                     scanner.getCurrentTokenStartPosition()));
914                     break;
915                 }
916               }
917
918             } else {
919               ident = scanner.getCurrentIdentifierSource();
920
921               current.add(new PHPVarDeclaration(current, variableName,
922               //          chIndx - ident.length
923               scanner.getCurrentTokenStartPosition()));
924             }
925           }
926         } else if (token == TokenNamefunction) {
927           getNextToken();
928           if (token == TokenNameAND) {
929             getNextToken();
930           }
931           if (token == TokenNameIdentifier && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
932             ident = scanner.getCurrentIdentifierSource();
933             outlineInfo.addVariable(new String(ident));
934             temp = new PHPFunctionDeclaration(current, new String(ident),
935               // chIndx - ident.length
936   scanner.getCurrentTokenStartPosition());
937             current.add(temp);
938             getNextToken();
939             parseDeclarations(outlineInfo, temp, true);
940           }
941         } else if (token == TokenNameclass) {
942           getNextToken();
943           if (token == TokenNameIdentifier && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
944             ident = scanner.getCurrentIdentifierSource();
945             outlineInfo.addVariable(new String(ident));
946             temp = new PHPClassDeclaration(current, new String(ident),
947               //      chIndx - ident.len
948   scanner.getCurrentTokenStartPosition());
949             current.add(temp);
950             //        stack.push(temp);
951             getNextToken();
952
953             //skip tokens for classname, extends and others until we have the opening '{'
954             while (token != TokenNameLBRACE && token != TokenNameEOF && token != TokenNameERROR) {
955               getNextToken();
956             }
957             parseDeclarations(outlineInfo, temp, true);
958             //        stack.pop();
959           }
960         } else if ((token == TokenNameLBRACE) || (token == TokenNameDOLLAR_LBRACE)) {
961           getNextToken();
962           counter++;
963         } else if (token == TokenNameRBRACE) {
964           getNextToken();
965           --counter;
966           if (counter == 0 && goBack) {
967             return;
968           }
969         } else if (token == TokenNamerequire || token == TokenNamerequire_once || token == TokenNameinclude || token == TokenNameinclude_once) {
970           ident = scanner.getCurrentTokenSource();
971
972           getNextToken();
973           int startPosition = scanner.getCurrentTokenStartPosition();
974           expression();
975           char[] expr = scanner.getCurrentTokenSource(startPosition);
976           outlineInfo.addVariable(new String(ident));
977           current.add(new PHPReqIncDeclaration(current, new String(ident),
978           //    chIndx - ident.length,
979           startPosition, new String(expr)));
980           getNextToken();
981         } else {
982           getNextToken();
983         }
984       }
985     } catch (CoreException e) {
986     } catch (SyntaxError sytaxErr) {
987       try {
988         //  setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
989         setMarker(sytaxErr.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
990       } catch (CoreException e) {
991       }
992     }
993   }
994
995   private void statementList() throws CoreException {
996     do {
997       statement(TokenNameEOF);
998       if ((token == TokenNameRBRACE)
999         || (token == TokenNamecase)
1000         || (token == TokenNamedefault)
1001         || (token == TokenNameelse)
1002         || (token == TokenNameelseif)
1003         || (token == TokenNameendif)
1004         || (token == TokenNameendfor)
1005         || (token == TokenNameendforeach)
1006         || (token == TokenNameendwhile)
1007         || (token == TokenNameendswitch)
1008         || (token == TokenNameEOF)
1009         || (token == TokenNameERROR)) {
1010         return;
1011       }
1012     } while (true);
1013   }
1014
1015   private void functionBody(MethodDeclaration methodDecl) throws CoreException {
1016     // '{' [statement-list] '}'
1017     if (token == TokenNameLBRACE) {
1018       getNextToken();
1019     } else {
1020       throwSyntaxError("'{' expected in compound-statement.");
1021     }
1022     if (token != TokenNameRBRACE) {
1023       statementList();
1024     }
1025     if (token == TokenNameRBRACE) {
1026       methodDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1027       getNextToken();
1028     } else {
1029       throwSyntaxError("'}' expected in compound-statement.");
1030     }
1031   }
1032
1033   private void statement(int previousToken) throws CoreException {
1034     //   if (token > TokenNameKEYWORD && token != TokenNamelist && token != TokenNamenew) {
1035     //  char[] ident = scanner.getCurrentIdentifierSource();
1036     //  String keyword = new String(ident);
1037     if (token == TokenNameinclude || token == TokenNameinclude_once) {
1038       getNextToken();
1039       if (token == TokenNameLPAREN) {
1040         expression();
1041         if (token == TokenNameSEMICOLON) {
1042           getNextToken();
1043         } else {
1044           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1045             throwSyntaxError("';' expected after 'include' or 'include_once'.");
1046           }
1047           //        getNextToken();
1048         }
1049       } else {
1050         concatenationExpression();
1051       }
1052
1053       return;
1054     } else if (token == TokenNamerequire || token == TokenNamerequire_once) {
1055       getNextToken();
1056       //constant();
1057       if (token == TokenNameLPAREN) {
1058         expression();
1059         if (token == TokenNameSEMICOLON) {
1060           getNextToken();
1061         } else {
1062           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1063             throwSyntaxError("';' expected after 'require' or 'require_once'.");
1064           }
1065           //        getNextToken();
1066         }
1067       } else {
1068         concatenationExpression();
1069       }
1070       return;
1071     } else if (token == TokenNameif) {
1072       getNextToken();
1073       if (token == TokenNameLPAREN) {
1074         getNextToken();
1075       } else {
1076         throwSyntaxError("'(' expected after 'if' keyword.");
1077       }
1078       expression();
1079       if (token == TokenNameRPAREN) {
1080         getNextToken();
1081       } else {
1082         throwSyntaxError("')' expected after 'if' condition.");
1083       }
1084       ifStatement();
1085       return;
1086
1087     } else if (token == TokenNameswitch) {
1088       getNextToken();
1089       if (token == TokenNameLPAREN) {
1090         getNextToken();
1091       } else {
1092         throwSyntaxError("'(' expected after 'switch' keyword.");
1093       }
1094       expression();
1095       if (token == TokenNameRPAREN) {
1096         getNextToken();
1097       } else {
1098         throwSyntaxError("')' expected after 'switch' condition.");
1099       }
1100       switchStatement();
1101       return;
1102     } else if (token == TokenNamefor) {
1103       getNextToken();
1104       if (token == TokenNameLPAREN) {
1105         getNextToken();
1106       } else {
1107         throwSyntaxError("'(' expected after 'for' keyword.");
1108       }
1109       if (token == TokenNameSEMICOLON) {
1110         getNextToken();
1111       } else {
1112         expressionList();
1113         if (token == TokenNameSEMICOLON) {
1114           getNextToken();
1115         } else {
1116           throwSyntaxError("';' expected after 'for'.");
1117         }
1118       }
1119       if (token == TokenNameSEMICOLON) {
1120         getNextToken();
1121       } else {
1122         expressionList();
1123         if (token == TokenNameSEMICOLON) {
1124           getNextToken();
1125         } else {
1126           throwSyntaxError("';' expected after 'for'.");
1127         }
1128       }
1129       if (token == TokenNameRPAREN) {
1130         getNextToken();
1131       } else {
1132         expressionList();
1133         if (token == TokenNameRPAREN) {
1134           getNextToken();
1135         } else {
1136           throwSyntaxError("')' expected after 'for'.");
1137         }
1138       }
1139       forStatement();
1140       return;
1141     } else if (token == TokenNamewhile) {
1142       getNextToken();
1143       if (token == TokenNameLPAREN) {
1144         getNextToken();
1145       } else {
1146         throwSyntaxError("'(' expected after 'while' keyword.");
1147       }
1148       expression();
1149       if (token == TokenNameRPAREN) {
1150         getNextToken();
1151       } else {
1152         throwSyntaxError("')' expected after 'while' condition.");
1153       }
1154       whileStatement();
1155       return;
1156     } else if (token == TokenNamedo) {
1157       getNextToken();
1158       if (token == TokenNameLBRACE) {
1159         getNextToken();
1160       } else {
1161         throwSyntaxError("'{' expected after 'do' keyword.");
1162       }
1163       if (token != TokenNameRBRACE) {
1164         statementList();
1165       }
1166       if (token == TokenNameRBRACE) {
1167         getNextToken();
1168       } else {
1169         throwSyntaxError("'}' expected after 'do' keyword.");
1170       }
1171       if (token == TokenNamewhile) {
1172         getNextToken();
1173         if (token == TokenNameLPAREN) {
1174           getNextToken();
1175         } else {
1176           throwSyntaxError("'(' expected after 'while' keyword.");
1177         }
1178         expression();
1179         if (token == TokenNameRPAREN) {
1180           getNextToken();
1181         } else {
1182           throwSyntaxError("')' expected after 'while' condition.");
1183         }
1184       } else {
1185         throwSyntaxError("'while' expected after 'do' keyword.");
1186       }
1187       if (token == TokenNameSEMICOLON) {
1188         getNextToken();
1189       } else {
1190         if (token != TokenNameStopPHP) {
1191           throwSyntaxError("';' expected after do-while statement.");
1192         }
1193         getNextToken();
1194       }
1195       return;
1196     } else if (token == TokenNameforeach) {
1197       getNextToken();
1198       if (token == TokenNameLPAREN) {
1199         getNextToken();
1200       } else {
1201         throwSyntaxError("'(' expected after 'foreach' keyword.");
1202       }
1203       expression();
1204       if (token == TokenNameas) {
1205         getNextToken();
1206       } else {
1207         throwSyntaxError("'as' expected after 'foreach' exxpression.");
1208       }
1209       variable();
1210       if (token == TokenNameEQUAL_GREATER) {
1211         getNextToken();
1212         variable();
1213       }
1214       if (token == TokenNameRPAREN) {
1215         getNextToken();
1216       } else {
1217         throwSyntaxError("')' expected after 'foreach' expression.");
1218       }
1219       foreachStatement();
1220       return;
1221
1222     } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) {
1223       getNextToken();
1224       if (token != TokenNameSEMICOLON) {
1225         expression();
1226       }
1227       if (token == TokenNameSEMICOLON) {
1228         getNextToken();
1229       } else {
1230         if (token != TokenNameStopPHP) {
1231           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
1232         }
1233         getNextToken();
1234       }
1235       return;
1236
1237     } else if (token == TokenNameecho) {
1238       getNextToken();
1239       expressionList();
1240       if (token == TokenNameSEMICOLON) {
1241         getNextToken();
1242       } else {
1243         if (token != TokenNameStopPHP) {
1244           throwSyntaxError("';' expected after 'echo' statement.");
1245         }
1246         getNextToken();
1247       }
1248       return;
1249       //    } else if (token == TokenNameprint) {
1250       //      getNextToken();
1251       //      expression();
1252       //      if (token == TokenNameSEMICOLON) {
1253       //        getNextToken();
1254       //      } else {
1255       //        if (token != TokenNameStopPHP) {
1256       //          throwSyntaxError("';' expected after 'print' statement.");
1257       //        }
1258       //        getNextToken();
1259       //      }
1260       //      return;
1261
1262     } else if (token == TokenNameglobal || token == TokenNamestatic) {
1263       getNextToken();
1264       variableList();
1265       if (token == TokenNameSEMICOLON) {
1266         getNextToken();
1267       } else {
1268         if (token != TokenNameStopPHP) {
1269           throwSyntaxError("';' expected after 'global' or 'static' statement.");
1270         }
1271         getNextToken();
1272       }
1273       return;
1274
1275       //      } else if (token == TokenNameunset) {
1276       //        getNextToken();
1277       //        if (token == TokenNameARGOPEN) {
1278       //          getNextToken();
1279       //        } else {
1280       //          throwSyntaxError("'(' expected after 'unset' keyword.");
1281       //        }
1282       //        variableList();
1283       //        if (token == TokenNameARGCLOSE) {
1284       //          getNextToken();
1285       //        } else {
1286       //          throwSyntaxError("')' expected after 'unset' statement.");
1287       //        }
1288       //        if (token == TokenNameSEMICOLON) {
1289       //          getNextToken();
1290       //        } else {
1291       //          if (token != TokenNameStopPHP) {
1292       //            throwSyntaxError("';' expected after 'unset' statement.");
1293       //          }
1294       //          getNextToken();
1295       //        }
1296       //        return;
1297
1298       //      } else if (token == TokenNameexit || token == TokenNamedie) {
1299       //        getNextToken();
1300       //        if (token != TokenNameSEMICOLON) {
1301       //          exitStatus();
1302       //        }
1303       //        if (token == TokenNameSEMICOLON) {
1304       //          getNextToken();
1305       //        } else {
1306       //          if (token != TokenNameStopPHP) {
1307       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
1308       //          }
1309       //          getNextToken();
1310       //        }
1311       //        return;
1312
1313     } else if (token == TokenNamedefine) {
1314       getNextToken();
1315       if (token == TokenNameLPAREN) {
1316         getNextToken();
1317       } else {
1318         throwSyntaxError("'(' expected after 'define' keyword.");
1319       }
1320       expression();
1321       if (token == TokenNameCOMMA) {
1322         getNextToken();
1323       } else {
1324         throwSyntaxError("',' expected after first 'define' constant.");
1325       }
1326       expression();
1327       if (token == TokenNameCOMMA) {
1328         getNextToken();
1329         expression();
1330       }
1331       if (token == TokenNameRPAREN) {
1332         getNextToken();
1333       } else {
1334         throwSyntaxError("')' expected after 'define' statement.");
1335       }
1336       if (token == TokenNameSEMICOLON) {
1337         getNextToken();
1338       } else {
1339         if (token != TokenNameStopPHP) {
1340           throwSyntaxError("';' expected after 'define' statement.");
1341         }
1342         getNextToken();
1343       }
1344       return;
1345     } else if (token == TokenNamefunction) {
1346       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1347       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1348       getNextToken();
1349       functionDefinition(methodDecl);
1350       return;
1351     } else if (token == TokenNameclass) {
1352       TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
1353       typeDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1354       // default super class
1355       typeDecl.superclass = new SingleTypeReference(TypeConstants.OBJECT, 0);
1356       compilationUnit.types.add(typeDecl);
1357       try {
1358         pushOnAstStack(typeDecl);
1359         getNextToken();
1360         classDeclarator(typeDecl);
1361         classBody(typeDecl);
1362       } finally {
1363         astPtr--;
1364         astLengthPtr--;
1365       }
1366       return;
1367       //      } else {
1368       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
1369     } else if (token == TokenNameLBRACE) {
1370       getNextToken();
1371       if (token != TokenNameRBRACE) {
1372         statementList();
1373       }
1374       if (token == TokenNameRBRACE) {
1375         getNextToken();
1376         return;
1377       } else {
1378         throwSyntaxError("'}' expected.");
1379       }
1380     } else {
1381       if (token != TokenNameSEMICOLON) {
1382         expression();
1383       }
1384       if (token == TokenNameSEMICOLON) {
1385         getNextToken();
1386         return;
1387       } else {
1388         if (token != TokenNameStopPHP && token != TokenNameEOF) {
1389           throwSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
1390         }
1391         getNextToken();
1392       }
1393     }
1394   }
1395
1396   private void classDeclarator(TypeDeclaration typeDecl) throws CoreException {
1397     //identifier
1398     //identifier 'extends' identifier
1399
1400     if (token == TokenNameIdentifier) {
1401       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1402       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1403       typeDecl.name = scanner.getCurrentIdentifierSource();
1404       getNextToken();
1405       if (token == TokenNameextends) {
1406         do {
1407           getNextToken();
1408           if (token == TokenNameIdentifier) {
1409             getNextToken();
1410           } else {
1411             reportSyntaxError("Class name expected after keyword 'extends'.", scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
1412             //            throwSyntaxError("ClassDeclaration name expected after keyword 'extends'.");
1413           }
1414         } while (token == TokenNameCOMMA);
1415       } 
1416     } else {
1417       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1418       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1419
1420       if (token > TokenNameKEYWORD) {
1421         typeDecl.name = scanner.getCurrentIdentifierSource();
1422         reportSyntaxError(
1423           "Don't use keyword for class declaration [" + scanner.toStringAction(token) + "].",
1424                                   typeDecl.sourceStart,
1425                                   typeDecl.sourceEnd);
1426         //        throwSyntaxError("Don't use keyword for class declaration [" + token + "].");
1427       }
1428       typeDecl.name = new char[] { ' ' };
1429       reportSyntaxError("Class name expected after keyword 'class'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1430       //      throwSyntaxError("ClassDeclaration name expected after keyword 'class'.");
1431     }
1432   }
1433
1434   private void classBody(TypeDeclaration typeDecl) throws CoreException {
1435     //'{' [class-element-list] '}'
1436     if (token == TokenNameLBRACE) {
1437       getNextToken();
1438       if (token != TokenNameRBRACE) {
1439         classElementList();
1440       }
1441       if (token == TokenNameRBRACE) {
1442         typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1443         getNextToken();
1444       } else {
1445         throwSyntaxError("'}' expected at end of class body.");
1446       }
1447     } else {
1448       throwSyntaxError("'{' expected at start of class body.");
1449     }
1450   }
1451
1452   private void classElementList() throws CoreException {
1453     do {
1454       classElement();
1455     } while (token == TokenNamefunction || token == TokenNamevar);
1456   }
1457
1458   private void classElement() throws CoreException {
1459     //class-property
1460     //function-definition
1461     if (token == TokenNamefunction) {
1462       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1463       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1464       getNextToken();
1465       functionDefinition(methodDecl);
1466     } else if (token == TokenNamevar) {
1467       getNextToken();
1468       classProperty();
1469     } else {
1470       throwSyntaxError("'function' or 'var' expected.");
1471     }
1472   }
1473
1474   private void classProperty() throws CoreException {
1475     //'var' variable ';'
1476     //'var' variable '=' constant ';'
1477     do {
1478       if (token == TokenNameVariable) {
1479         getNextToken();
1480         if (token == TokenNameEQUAL) {
1481           getNextToken();
1482           constant();
1483         }
1484       } else {
1485         if (token == TokenNamethis) {
1486           throwSyntaxError("Reserved word '$this' not allowed after keyword 'var'.");
1487         }
1488         throwSyntaxError("Variable expected after keyword 'var'.");
1489       }
1490       if (token != TokenNameCOMMA) {
1491         break;
1492       }
1493       getNextToken();
1494     } while (true);
1495     if (token == TokenNameSEMICOLON) {
1496       getNextToken();
1497     } else {
1498       throwSyntaxError("';' expected after variable declaration.");
1499     }
1500   }
1501
1502   private void functionDefinition(MethodDeclaration methodDecl) throws CoreException {
1503     if (astPtr == 0) {
1504       compilationUnit.types.add(methodDecl);
1505     } else {
1506       AstNode node = astStack[astPtr];
1507       if (node instanceof TypeDeclaration) {
1508         TypeDeclaration typeDecl = ((TypeDeclaration) node);
1509         if (typeDecl.methods == null) {
1510           typeDecl.methods = new AbstractMethodDeclaration[] { methodDecl };
1511         } else {
1512           AbstractMethodDeclaration[] newMethods;
1513           System.arraycopy(typeDecl.methods, 0, newMethods = new AbstractMethodDeclaration[typeDecl.methods.length + 1], 1, typeDecl.methods.length);
1514           newMethods[0] = methodDecl;
1515           typeDecl.methods = newMethods;
1516         }
1517       }
1518     }
1519     functionDeclarator(methodDecl);
1520     functionBody(methodDecl);
1521   }
1522
1523   private void functionDeclarator(MethodDeclaration methodDecl) throws CoreException {
1524     //identifier '(' [parameter-list] ')'
1525     if (token == TokenNameAND) {
1526       getNextToken();
1527     }
1528     if (token == TokenNameIdentifier) {
1529       methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1530       methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1531       methodDecl.selector = scanner.getCurrentIdentifierSource();
1532       getNextToken();
1533       if (token == TokenNameLPAREN) {
1534         getNextToken();
1535       } else {
1536         throwSyntaxError("'(' expected in function declaration.");
1537       }
1538       if (token != TokenNameRPAREN) {
1539         parameterList();
1540       }
1541       if (token != TokenNameRPAREN) {
1542         throwSyntaxError("')' expected in function declaration.");
1543       } else {
1544         methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1;
1545         getNextToken();
1546       }
1547     } else {
1548       if (token > TokenNameKEYWORD) {
1549         throwSyntaxError("Don't use keyword for function declaration [" + token + "].");
1550       }
1551       throwSyntaxError("Function name expected after keyword 'function'.");
1552     }
1553   }
1554   //
1555   private void parameterList() throws CoreException {
1556     //parameter-declaration
1557     //parameter-list ',' parameter-declaration
1558     do {
1559       parameterDeclaration();
1560       if (token != TokenNameCOMMA) {
1561         break;
1562       }
1563       getNextToken();
1564     } while (true);
1565   }
1566
1567   private void parameterDeclaration() throws CoreException {
1568     //variable
1569     //variable-reference
1570     if (token == TokenNameAND) {
1571       getNextToken();
1572       if (isVariable()) {
1573         getNextToken();
1574       } else {
1575         throwSyntaxError("Variable expected after reference operator '&'.");
1576       }
1577     }
1578     //variable '=' constant
1579     if (token == TokenNameVariable) {
1580       getNextToken();
1581       if (token == TokenNameEQUAL) {
1582         getNextToken();
1583         constant();
1584       }
1585       return;
1586     }
1587     if (token == TokenNamethis) {
1588       throwSyntaxError("Reserved word '$this' not allowed in parameter declaration.");
1589     }
1590   }
1591
1592   private void labeledStatementList() throws CoreException {
1593     if (token != TokenNamecase && token != TokenNamedefault) {
1594       throwSyntaxError("'case' or 'default' expected.");
1595     }
1596     do {
1597       if (token == TokenNamecase) {
1598         getNextToken();
1599         expression(); //constant();
1600         if (token == TokenNameCOLON) {
1601           getNextToken();
1602           if (token == TokenNamecase || token == TokenNamedefault) { // empty case statement ?
1603             continue;
1604           }
1605           statementList();
1606         } else if (token == TokenNameSEMICOLON) {
1607           //          setMarker(
1608           //            "':' expected after 'case' keyword (Found token: "
1609           //              + scanner.toStringAction(token)
1610           //              + ")",
1611           //            rowCount,
1612           //            PHPParser.INFO);
1613           setMarker(
1614             "':' expected after 'case' keyword (Found token: " + scanner.toStringAction(token) + ")",
1615             scanner.getCurrentTokenStartPosition(),
1616             scanner.getCurrentTokenEndPosition(),
1617             INFO);
1618           getNextToken();
1619           if (token == TokenNamecase) { // empty case statement ?
1620             continue;
1621           }
1622           statementList();
1623         } else {
1624           throwSyntaxError("':' character after 'case' constant expected (Found token: " + scanner.toStringAction(token) + ")");
1625         }
1626       } else { // TokenNamedefault
1627         getNextToken();
1628         if (token == TokenNameCOLON) {
1629           getNextToken();
1630           statementList();
1631         } else {
1632           throwSyntaxError("':' character after 'default' expected.");
1633         }
1634       }
1635     } while (token == TokenNamecase || token == TokenNamedefault);
1636   }
1637
1638   //  public void labeledStatement() {
1639   //    if (token == TokenNamecase) {
1640   //      getNextToken();
1641   //      constant();
1642   //      if (token == TokenNameDDOT) {
1643   //        getNextToken();
1644   //        statement();
1645   //      } else {
1646   //        throwSyntaxError("':' character after 'case' constant expected.");
1647   //      }
1648   //      return;
1649   //    } else if (token == TokenNamedefault) {
1650   //      getNextToken();
1651   //      if (token == TokenNameDDOT) {
1652   //        getNextToken();
1653   //        statement();
1654   //      } else {
1655   //        throwSyntaxError("':' character after 'default' expected.");
1656   //      }
1657   //      return;
1658   //    }
1659   //  }
1660
1661   //  public void expressionStatement() {
1662   //  }
1663
1664   //  private void inclusionStatement() {
1665   //  }
1666
1667   //  public void compoundStatement() {
1668   //  }
1669
1670   //  public void selectionStatement() {
1671   //  }
1672   //
1673   //  public void iterationStatement() {
1674   //  }
1675   //
1676   //  public void jumpStatement() {
1677   //  }
1678   //
1679   //  public void outputStatement() {
1680   //  }
1681   //
1682   //  public void scopeStatement() {
1683   //  }
1684   //
1685   //  public void flowStatement() {
1686   //  }
1687   //
1688   //  public void definitionStatement() {
1689   //  }
1690
1691   private void ifStatement() throws CoreException {
1692     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1693     if (token == TokenNameCOLON) {
1694       getNextToken();
1695       if (token != TokenNameendif) {
1696         statementList();
1697         switch (token) {
1698           case TokenNameelse :
1699             getNextToken();
1700             if (token == TokenNameCOLON) {
1701               getNextToken();
1702               if (token != TokenNameendif) {
1703                 statementList();
1704               }
1705             } else {
1706               if (token == TokenNameif) { //'else if'
1707                 getNextToken();
1708                 elseifStatementList();
1709               } else {
1710                 throwSyntaxError("':' expected after 'else'.");
1711               }
1712             }
1713             break;
1714           case TokenNameelseif :
1715             getNextToken();
1716             elseifStatementList();
1717             break;
1718         }
1719       }
1720
1721       if (token != TokenNameendif) {
1722         throwSyntaxError("'endif' expected.");
1723       }
1724       getNextToken();
1725       if (token != TokenNameSEMICOLON) {
1726         throwSyntaxError("';' expected after if-statement.");
1727       }
1728       getNextToken();
1729     } else {
1730       // statement [else-statement]
1731       statement(TokenNameEOF);
1732       if (token == TokenNameelseif) {
1733         getNextToken();
1734         if (token == TokenNameLPAREN) {
1735           getNextToken();
1736         } else {
1737           throwSyntaxError("'(' expected after 'elseif' keyword.");
1738         }
1739         expression();
1740         if (token == TokenNameRPAREN) {
1741           getNextToken();
1742         } else {
1743           throwSyntaxError("')' expected after 'elseif' condition.");
1744         }
1745         ifStatement();
1746       } else if (token == TokenNameelse) {
1747         getNextToken();
1748         statement(TokenNameEOF);
1749       }
1750     }
1751   }
1752
1753   private void elseifStatementList() throws CoreException {
1754     do {
1755       elseifStatement();
1756       switch (token) {
1757         case TokenNameelse :
1758           getNextToken();
1759           if (token == TokenNameCOLON) {
1760             getNextToken();
1761             if (token != TokenNameendif) {
1762               statementList();
1763             }
1764             return;
1765           } else {
1766             if (token == TokenNameif) { //'else if'
1767               getNextToken();
1768             } else {
1769               throwSyntaxError("':' expected after 'else'.");
1770             }
1771           }
1772           break;
1773         case TokenNameelseif :
1774           getNextToken();
1775           break;
1776         default :
1777           return;
1778       }
1779     } while (true);
1780   }
1781
1782   private void elseifStatement() throws CoreException {
1783     if (token == TokenNameLPAREN) {
1784       getNextToken();
1785       expression();
1786       if (token != TokenNameRPAREN) {
1787         throwSyntaxError("')' expected in else-if-statement.");
1788       }
1789       getNextToken();
1790       if (token != TokenNameCOLON) {
1791         throwSyntaxError("':' expected in else-if-statement.");
1792       }
1793       getNextToken();
1794       if (token != TokenNameendif) {
1795         statementList();
1796       }
1797     }
1798   }
1799
1800   private void switchStatement() throws CoreException {
1801     if (token == TokenNameCOLON) {
1802       // ':' [labeled-statement-list] 'endswitch' ';'
1803       getNextToken();
1804       labeledStatementList();
1805       if (token != TokenNameendswitch) {
1806         throwSyntaxError("'endswitch' expected.");
1807       }
1808       getNextToken();
1809       if (token != TokenNameSEMICOLON) {
1810         throwSyntaxError("';' expected after switch-statement.");
1811       }
1812       getNextToken();
1813     } else {
1814       // '{' [labeled-statement-list] '}'
1815       if (token != TokenNameLBRACE) {
1816         throwSyntaxError("'{' expected in switch statement.");
1817       }
1818       getNextToken();
1819       if (token != TokenNameRBRACE) {
1820         labeledStatementList();
1821       }
1822       if (token != TokenNameRBRACE) {
1823         throwSyntaxError("'}' expected in switch statement.");
1824       }
1825       getNextToken();
1826
1827     }
1828   }
1829
1830   private void forStatement() throws CoreException {
1831     if (token == TokenNameCOLON) {
1832       getNextToken();
1833       statementList();
1834       if (token != TokenNameendfor) {
1835         throwSyntaxError("'endfor' expected.");
1836       }
1837       getNextToken();
1838       if (token != TokenNameSEMICOLON) {
1839         throwSyntaxError("';' expected after for-statement.");
1840       }
1841       getNextToken();
1842     } else {
1843       statement(TokenNameEOF);
1844     }
1845   }
1846
1847   private void whileStatement() throws CoreException {
1848     // ':' statement-list 'endwhile' ';'
1849     if (token == TokenNameCOLON) {
1850       getNextToken();
1851       statementList();
1852       if (token != TokenNameendwhile) {
1853         throwSyntaxError("'endwhile' expected.");
1854       }
1855       getNextToken();
1856       if (token != TokenNameSEMICOLON) {
1857         throwSyntaxError("';' expected after while-statement.");
1858       }
1859       getNextToken();
1860     } else {
1861       statement(TokenNameEOF);
1862     }
1863   }
1864
1865   private void foreachStatement() throws CoreException {
1866     if (token == TokenNameCOLON) {
1867       getNextToken();
1868       statementList();
1869       if (token != TokenNameendforeach) {
1870         throwSyntaxError("'endforeach' expected.");
1871       }
1872       getNextToken();
1873       if (token != TokenNameSEMICOLON) {
1874         throwSyntaxError("';' expected after foreach-statement.");
1875       }
1876       getNextToken();
1877     } else {
1878       statement(TokenNameEOF);
1879     }
1880   }
1881
1882   private void exitStatus() throws CoreException {
1883     if (token == TokenNameLPAREN) {
1884       getNextToken();
1885     } else {
1886       throwSyntaxError("'(' expected in 'exit-status'.");
1887     }
1888     if (token != TokenNameRPAREN) {
1889       expression();
1890     }
1891     if (token == TokenNameRPAREN) {
1892       getNextToken();
1893     } else {
1894       throwSyntaxError("')' expected after 'exit-status'.");
1895     }
1896   }
1897
1898   private void expressionList() throws CoreException {
1899     do {
1900       expression();
1901       if (token == TokenNameCOMMA) {
1902         getNextToken();
1903       } else {
1904         break;
1905       }
1906     } while (true);
1907   }
1908
1909   private void expression() throws CoreException {
1910     //todo: find a better way to get the expression
1911     //    expression = new StringBuffer();
1912     //    for (int i = chIndx; i < str.length(); i++) {
1913     //      if (str.charAt(i) == ';') {
1914     //        break;
1915     //      }
1916     //      expression.append(str.charAt(i));
1917     //    }
1918
1919     //    if (token == TokenNameSTRING_CONSTANT || token == TokenNameINTERPOLATED_STRING) {
1920     //      getNextToken();
1921     //    } else {
1922     logicalinclusiveorExpression();
1923     //      while (token != TokenNameSEMICOLON) {
1924     //        getNextToken();
1925     //      //      }
1926     //    }
1927   }
1928
1929   private void postfixExpression() throws CoreException {
1930     //  String ident;
1931     char[] ident;
1932     boolean castFlag = false;
1933     boolean arrayFlag = false;
1934     switch (token) {
1935       case TokenNamenew :
1936         getNextToken();
1937         expression();
1938         break;
1939       case TokenNamenull :
1940         getNextToken();
1941         break;
1942       case TokenNamefalse :
1943         getNextToken();
1944         break;
1945       case TokenNametrue :
1946         getNextToken();
1947         break;
1948       case TokenNameStringConstant :
1949         getNextToken();
1950         break;
1951       case TokenNameHEREDOC :
1952       case TokenNameStringInterpolated :
1953       case TokenNameStringLiteral :
1954         getNextToken();
1955         break;
1956       case TokenNameLPAREN :
1957         getNextToken();
1958
1959         if (token == TokenNameIdentifier) {
1960           // check if identifier is a type:
1961           //    ident = identifier;
1962           ident = scanner.getCurrentIdentifierSource();
1963           String str = new String(ident).toLowerCase();
1964           for (int i = 0; i < PHP_TYPES.length; i++) {
1965             if (PHP_TYPES[i].equals(str)) {
1966               castFlag = true;
1967               if (PHP_TYPES[i].equals("array")) {
1968                 arrayFlag = true;
1969               }
1970               break;
1971             }
1972           }
1973         }
1974
1975         if (castFlag) {
1976           getNextToken();
1977           if (arrayFlag && token == TokenNameLPAREN) {
1978             getNextToken();
1979             if (token == TokenNameRPAREN) {
1980               getNextToken();
1981             } else {
1982               expression();
1983               if (token != TokenNameRPAREN) {
1984                 throwSyntaxError(") expected after 'array('.");
1985               }
1986             }
1987           }
1988           if (token != TokenNameRPAREN) {
1989             throwSyntaxError(") expected after cast-type '" + str + "'.");
1990           }
1991           getNextToken();
1992           expression();
1993           break;
1994         } else {
1995           expression();
1996         }
1997         if (token != TokenNameRPAREN) {
1998           throwSyntaxError(") expected in postfix-expression.");
1999         }
2000         getNextToken();
2001         break;
2002       case TokenNameDoubleLiteral :
2003         getNextToken();
2004         break;
2005       case TokenNameIntegerLiteral :
2006         getNextToken();
2007         break;
2008       case TokenNameDOLLAR_LBRACE :
2009         getNextToken();
2010         expression();
2011         if (token != TokenNameRBRACE) {
2012           throwSyntaxError("'}' expected after indirect variable token '${'.");
2013         }
2014         getNextToken();
2015         break;
2016       case TokenNameVariable :
2017       case TokenNamethis :
2018         ident = scanner.getCurrentIdentifierSource();
2019         getNextToken();
2020         if (token == TokenNameLBRACE) {
2021           getNextToken();
2022           expression();
2023           if (token != TokenNameRBRACE) {
2024             throwSyntaxError("'}' expected after variable '" + new String(ident) + "' in variable-expression.");
2025           }
2026           getNextToken();
2027         } else if (token == TokenNameLPAREN) {
2028           getNextToken();
2029           if (token != TokenNameRPAREN) {
2030             expressionList();
2031             if (token != TokenNameRPAREN) {
2032               throwSyntaxError("')' expected after variable '" + new String(ident) + "' in postfix-expression.");
2033             }
2034           }
2035           getNextToken();
2036         }
2037         break;
2038       case TokenNameIdentifier :
2039         ident = scanner.getCurrentIdentifierSource();
2040         getNextToken();
2041         if (token == TokenNameLPAREN) {
2042           getNextToken();
2043           if (token != TokenNameRPAREN) {
2044             expressionList();
2045             if (token != TokenNameRPAREN) {
2046               throwSyntaxError(
2047                 "')' expected after identifier '" + new String(ident) + "' in postfix-expression." + "(Found token: " + scanner.toStringAction(token) + ")");
2048             }
2049           }
2050           getNextToken();
2051         }
2052         break;
2053       case TokenNameprint :
2054         getNextToken();
2055         expression();
2056         //        if (token == TokenNameSEMICOLON) {
2057         //          getNextToken();
2058         //        } else {
2059         //          if (token != TokenNameStopPHP) {
2060         //            throwSyntaxError("';' expected after 'print' statement.");
2061         //          }
2062         //          getNextToken();
2063         //        }
2064         break;
2065       case TokenNamelist :
2066         getNextToken();
2067         if (token == TokenNameLPAREN) {
2068           getNextToken();
2069           if (token == TokenNameCOMMA) {
2070             getNextToken();
2071           }
2072           expressionList();
2073           if (token != TokenNameRPAREN) {
2074             throwSyntaxError("')' expected after 'list' keyword.");
2075           }
2076           getNextToken();
2077           //          if (token == TokenNameSET) {
2078           //            getNextToken();
2079           //            logicalinclusiveorExpression();
2080           //          }
2081         } else {
2082           throwSyntaxError("'(' expected after 'list' keyword.");
2083         }
2084         break;
2085         //      case TokenNameexit :
2086         //        getNextToken();
2087         //        if (token != TokenNameSEMICOLON) {
2088         //          exitStatus();
2089         //        }
2090         //        if (token == TokenNameSEMICOLON) {
2091         //          getNextToken();
2092         //        } else {
2093         //          if (token != TokenNameStopPHP) {
2094         //            throwSyntaxError("';' expected after 'exit' expression.");
2095         //          }
2096         //          getNextToken();
2097         //        }
2098         //        break;
2099         //      case TokenNamedie :
2100         //        getNextToken();
2101         //        if (token != TokenNameSEMICOLON) {
2102         //          exitStatus();
2103         //        }
2104         //        if (token == TokenNameSEMICOLON) {
2105         //          getNextToken();
2106         //        } else {
2107         //          if (token != TokenNameStopPHP) {
2108         //            throwSyntaxError("';' expected after 'die' expression.");
2109         //          }
2110         //        }
2111         //        break;
2112
2113         //      case TokenNamearray :
2114         //        getNextToken();
2115         //        if (token == TokenNameARGOPEN) {
2116         //          getNextToken();
2117         //          if (token == TokenNameCOMMA) {
2118         //            getNextToken();
2119         //          }
2120         //          expressionList();
2121         //          if (token != TokenNameARGCLOSE) {
2122         //            throwSyntaxError("')' expected after 'list' keyword.");
2123         //          }
2124         //          getNextToken();
2125         //          if (token == TokenNameSET) {
2126         //            getNextToken();
2127         //            logicalinclusiveorExpression();
2128         //          }
2129         //        } else {
2130         //          throwSyntaxError("'(' expected after 'list' keyword.");
2131         //        }
2132         //        break;
2133     }
2134     boolean while_flag = true;
2135     do {
2136       switch (token) {
2137         case TokenNameLBRACKET :
2138           getNextToken();
2139           expression();
2140           if (token != TokenNameRBRACKET) {
2141             throwSyntaxError("] expected in postfix-expression.");
2142           }
2143           getNextToken();
2144           break;
2145         case TokenNameCOLON_COLON : // ::
2146         case TokenNameMINUS_GREATER : // ->
2147           getNextToken();
2148           if (token > TokenNameKEYWORD) {
2149             ident = scanner.getCurrentIdentifierSource();
2150             //            setMarker(
2151             //              "Avoid using keyword '"
2152             //                + new String(ident)
2153             //                + "' as variable name.",
2154             //              rowCount,
2155             //              PHPParser.INFO);
2156             setMarker(
2157               "Avoid using keyword '" + new String(ident) + "' as variable name.",
2158               scanner.getCurrentTokenStartPosition(),
2159               scanner.getCurrentTokenEndPosition(),
2160               INFO);
2161           }
2162           switch (token) {
2163             case TokenNameVariable :
2164               ident = scanner.getCurrentIdentifierSource();
2165               getNextToken();
2166               //              if (token == TokenNameARGOPEN) {
2167               //                getNextToken();
2168               //                expressionList();
2169               //                if (token != TokenNameARGCLOSE) {
2170               //                  throwSyntaxError(") expected after variable '" + ident + "'.");
2171               //                }
2172               //                getNextToken();
2173               //              }
2174               break;
2175             case TokenNameIdentifier :
2176               //ident = scanner.getCurrentIdentifierSource();
2177               getNextToken();
2178               break;
2179             case TokenNameLBRACE :
2180               getNextToken();
2181               expression();
2182               if (token != TokenNameRBRACE) {
2183                 throwSyntaxError("} expected in postfix-expression.");
2184               }
2185               getNextToken();
2186               break;
2187             default :
2188               throwSyntaxError("Syntax error after '->' token.");
2189           } while (token == TokenNameLBRACKET || token == TokenNameLPAREN || token == TokenNameLBRACE) {
2190               if (token == TokenNameLBRACKET) {
2191                 getNextToken();
2192                 expressionList();
2193                 if (token != TokenNameRBRACKET) {
2194                   throwSyntaxError("] expected after '->'.");
2195                 }
2196                 getNextToken();
2197               } else if (token == TokenNameLPAREN) {
2198                 getNextToken();
2199                 expressionList();
2200                 if (token != TokenNameRPAREN) {
2201                   throwSyntaxError(") expected after '->'.");
2202                 }
2203                 getNextToken();
2204               } else if (token == TokenNameLBRACE) {
2205                 getNextToken();
2206                 expression();
2207                 if (token != TokenNameRBRACE) {
2208                   throwSyntaxError("} expected after '->'.");
2209                 }
2210                 getNextToken();
2211               }
2212             }
2213           break;
2214         case TokenNamePLUS_PLUS :
2215           getNextToken();
2216           break;
2217         case TokenNameMINUS_MINUS :
2218           getNextToken();
2219           break;
2220         default :
2221           while_flag = false;
2222       }
2223
2224     }
2225     while (while_flag);
2226   }
2227
2228   private void unaryExpression() throws CoreException {
2229     switch (token) {
2230       case TokenNamePLUS_PLUS :
2231         getNextToken();
2232         unaryExpression();
2233         break;
2234       case TokenNameMINUS_MINUS :
2235         getNextToken();
2236         unaryExpression();
2237         break;
2238         // '@' '&' '*' '+' '-' '~' '!'
2239       case TokenNameAT :
2240         getNextToken();
2241         if (token == TokenNameinclude || token == TokenNameinclude_once || token == TokenNamerequire || token == TokenNamerequire_once) {
2242           statement(TokenNameAT);
2243         } else {
2244           postfixExpression(); //  castExpression();
2245         }
2246         break;
2247       case TokenNameAND :
2248         getNextToken();
2249         castExpression();
2250         break;
2251       case TokenNameMULTIPLY :
2252         getNextToken();
2253         castExpression();
2254         break;
2255       case TokenNamePLUS :
2256         getNextToken();
2257         castExpression();
2258         break;
2259       case TokenNameMINUS :
2260         getNextToken();
2261         castExpression();
2262         break;
2263       case TokenNameTWIDDLE :
2264         getNextToken();
2265         castExpression();
2266         break;
2267       case TokenNameNOT :
2268         getNextToken();
2269         castExpression();
2270         break;
2271       default :
2272         postfixExpression();
2273     }
2274   }
2275
2276   private void castExpression() throws CoreException {
2277     //    if (token == TokenNameARGOPEN) {
2278     //      getNextToken();
2279     //      typeName();
2280     //      if (token != TokenNameARGCLOSE) {
2281     //        throwSyntaxError(") expected after cast-expression.");
2282     //      }
2283     //      getNextToken();
2284     //    }
2285     unaryExpression();
2286   }
2287
2288   private void assignExpression() throws CoreException {
2289     castExpression();
2290     if (token == TokenNameEQUAL) { // =
2291       getNextToken();
2292       logicalinclusiveorExpression();
2293     } else if (token == TokenNameDOT_EQUAL) { // .=
2294       getNextToken();
2295       logicalinclusiveorExpression();
2296     } else if (token == TokenNameEQUAL_GREATER) { // =>
2297       getNextToken();
2298       logicalinclusiveorExpression();
2299     } else if (token == TokenNamePLUS_EQUAL) { // +=
2300       getNextToken();
2301       logicalinclusiveorExpression();
2302     } else if (token == TokenNameMINUS_EQUAL) { // -=
2303       getNextToken();
2304       logicalinclusiveorExpression();
2305     } else if (token == TokenNameMULTIPLY_EQUAL) { // *=
2306       getNextToken();
2307       logicalinclusiveorExpression();
2308     } else if (token == TokenNameDIVIDE_EQUAL) { // *=
2309       getNextToken();
2310       logicalinclusiveorExpression();
2311     } else if (token == TokenNameREMAINDER_EQUAL) { // %=
2312       getNextToken();
2313       logicalinclusiveorExpression();
2314     } else if (token == TokenNameAND_EQUAL) { // &=
2315       getNextToken();
2316       logicalinclusiveorExpression();
2317     } else if (token == TokenNameOR_EQUAL) { // |=
2318       getNextToken();
2319       logicalinclusiveorExpression();
2320     } else if (token == TokenNameXOR_EQUAL) { // ^=
2321       getNextToken();
2322       logicalinclusiveorExpression();
2323     } else if (token == TokenNameLEFT_SHIFT_EQUAL) { // <<=
2324       getNextToken();
2325       logicalinclusiveorExpression();
2326     } else if (token == TokenNameRIGHT_SHIFT_EQUAL) { // >>=
2327       getNextToken();
2328       logicalinclusiveorExpression();
2329     } else if (token == TokenNameTWIDDLE_EQUAL) { // ~=
2330       getNextToken();
2331       logicalinclusiveorExpression();
2332     }
2333   }
2334
2335   private void multiplicativeExpression() throws CoreException {
2336     do {
2337       assignExpression();
2338       if (token != TokenNameMULTIPLY && token != TokenNameDIVIDE && token != TokenNameREMAINDER) {
2339         return;
2340       }
2341       getNextToken();
2342     } while (true);
2343   }
2344
2345   private void concatenationExpression() throws CoreException {
2346     do {
2347       multiplicativeExpression();
2348       if (token != TokenNameDOT) {
2349         return;
2350       }
2351       getNextToken();
2352     } while (true);
2353   }
2354
2355   private void additiveExpression() throws CoreException {
2356     do {
2357       concatenationExpression();
2358       if (token != TokenNamePLUS && token != TokenNameMINUS) {
2359         return;
2360       }
2361       getNextToken();
2362     } while (true);
2363   }
2364
2365   private void shiftExpression() throws CoreException {
2366     do {
2367       additiveExpression();
2368       if (token != TokenNameLEFT_SHIFT && token != TokenNameRIGHT_SHIFT) {
2369         return;
2370       }
2371       getNextToken();
2372     } while (true);
2373   }
2374
2375   private void relationalExpression() throws CoreException {
2376     do {
2377       shiftExpression();
2378       if (token != TokenNameLESS && token != TokenNameGREATER && token != TokenNameLESS_EQUAL && token != TokenNameGREATER_EQUAL) {
2379         return;
2380       }
2381       getNextToken();
2382     } while (true);
2383   }
2384
2385   private void identicalExpression() throws CoreException {
2386     do {
2387       relationalExpression();
2388       if (token != TokenNameEQUAL_EQUAL_EQUAL && token != TokenNameNOT_EQUAL_EQUAL) {
2389         return;
2390       }
2391       getNextToken();
2392     } while (true);
2393   }
2394
2395   private void equalityExpression() throws CoreException {
2396     do {
2397       identicalExpression();
2398       if (token != TokenNameEQUAL_EQUAL && token != TokenNameNOT_EQUAL) {
2399         return;
2400       }
2401       getNextToken();
2402     } while (true);
2403   }
2404
2405   private void ternaryExpression() throws CoreException {
2406     equalityExpression();
2407     if (token == TokenNameQUESTION) {
2408       getNextToken();
2409       expression();
2410       if (token == TokenNameCOLON) {
2411         getNextToken();
2412         expression();
2413       } else {
2414         throwSyntaxError("':' expected in ternary operator '? :'.");
2415       }
2416     }
2417   }
2418
2419   private void andExpression() throws CoreException {
2420     do {
2421       ternaryExpression();
2422       if (token != TokenNameAND) {
2423         return;
2424       }
2425       getNextToken();
2426     } while (true);
2427   }
2428
2429   private void exclusiveorExpression() throws CoreException {
2430     do {
2431       andExpression();
2432       if (token != TokenNameXOR) {
2433         return;
2434       }
2435       getNextToken();
2436     } while (true);
2437   }
2438
2439   private void inclusiveorExpression() throws CoreException {
2440     do {
2441       exclusiveorExpression();
2442       if (token != TokenNameOR) {
2443         return;
2444       }
2445       getNextToken();
2446     } while (true);
2447   }
2448
2449   private void booleanandExpression() throws CoreException {
2450     do {
2451       inclusiveorExpression();
2452       if (token != TokenNameAND_AND) {
2453         return;
2454       }
2455       getNextToken();
2456     } while (true);
2457   }
2458
2459   private void booleanorExpression() throws CoreException {
2460     do {
2461       booleanandExpression();
2462       if (token != TokenNameOR_OR) {
2463         return;
2464       }
2465       getNextToken();
2466     } while (true);
2467   }
2468
2469   private void logicalandExpression() throws CoreException {
2470     do {
2471       booleanorExpression();
2472       if (token != TokenNameAND) {
2473         return;
2474       }
2475       getNextToken();
2476     } while (true);
2477   }
2478
2479   private void logicalexclusiveorExpression() throws CoreException {
2480     do {
2481       logicalandExpression();
2482       if (token != TokenNameXOR) {
2483         return;
2484       }
2485       getNextToken();
2486     } while (true);
2487   }
2488
2489   private void logicalinclusiveorExpression() throws CoreException {
2490     do {
2491       logicalexclusiveorExpression();
2492       if (token != TokenNameOR) {
2493         return;
2494       }
2495       getNextToken();
2496     } while (true);
2497   }
2498
2499   //  public void assignmentExpression() {
2500   //    if (token == TokenNameVARIABLE) {
2501   //      getNextToken();
2502   //      if (token == TokenNameSET) {
2503   //        getNextToken();
2504   //        logicalinclusiveorExpression();
2505   //      }
2506   //    } else {
2507   //      logicalinclusiveorExpression();
2508   //    }
2509   //  }
2510
2511   private void variableList() throws CoreException {
2512     do {
2513       variable();
2514       if (token == TokenNameCOMMA) {
2515         getNextToken();
2516       } else {
2517         break;
2518       }
2519     } while (true);
2520   }
2521
2522   private void variable() throws CoreException {
2523     if (token == TokenNameDOLLAR_LBRACE) {
2524       getNextToken();
2525       expression();
2526       ;
2527       if (token != TokenNameRBRACE) {
2528         throwSyntaxError("'}' expected after indirect variable token '${'.");
2529       }
2530       getNextToken();
2531     } else {
2532       if (token == TokenNameVariable) {
2533         getNextToken();
2534         if (token == TokenNameLBRACKET) {
2535           getNextToken();
2536           expression();
2537           if (token != TokenNameRBRACKET) {
2538             throwSyntaxError("']' expected in variable-list.");
2539           }
2540           getNextToken();
2541         } else if (token == TokenNameEQUAL) {
2542           getNextToken();
2543           constant();
2544         }
2545       } else {
2546         throwSyntaxError("$-variable expected in variable-list.");
2547       }
2548     }
2549   }
2550
2551   /**
2552    * It will look for a value (after a '=' for example)
2553    * @throws CoreException
2554    */
2555   private void constant() throws CoreException {
2556     //   String ident;
2557     switch (token) {
2558       case TokenNamePLUS :
2559         getNextToken();
2560         switch (token) {
2561           case TokenNameDoubleLiteral :
2562             getNextToken();
2563             break;
2564           case TokenNameIntegerLiteral :
2565             getNextToken();
2566             break;
2567           default :
2568             throwSyntaxError("Constant expected after '+' presign.");
2569         }
2570         break;
2571       case TokenNameMINUS :
2572         getNextToken();
2573         switch (token) {
2574           case TokenNameDoubleLiteral :
2575             getNextToken();
2576             break;
2577           case TokenNameIntegerLiteral :
2578             getNextToken();
2579             break;
2580           default :
2581             throwSyntaxError("Constant expected after '-' presign.");
2582         }
2583         break;
2584       case TokenNamenull :
2585         getNextToken();
2586         break;
2587       case TokenNamefalse :
2588         getNextToken();
2589         break;
2590       case TokenNametrue :
2591         getNextToken();
2592         break;
2593       case TokenNameIdentifier :
2594         //   ident = identifier;
2595         char[] ident = scanner.getCurrentIdentifierSource();
2596         getNextToken();
2597         if (token == TokenNameLPAREN) {
2598           getNextToken();
2599           if (token != TokenNameRPAREN) {
2600             expressionList();
2601             if (token != TokenNameRPAREN) {
2602               throwSyntaxError("')' expected after identifier '" + new String(ident) + "' in postfix-expression.");
2603             }
2604           }
2605           getNextToken();
2606         }
2607         break;
2608       case TokenNameStringLiteral :
2609         getNextToken();
2610         break;
2611       case TokenNameStringConstant :
2612         getNextToken();
2613         break;
2614       case TokenNameStringInterpolated :
2615         getNextToken();
2616         break;
2617       case TokenNameDoubleLiteral :
2618         getNextToken();
2619         break;
2620       case TokenNameIntegerLiteral :
2621         getNextToken();
2622         break;
2623       default :
2624         throwSyntaxError("Constant expected.");
2625     }
2626   }
2627
2628   public void reportSyntaxError() { //int act, int currentKind, int stateStackTop) {
2629
2630     /* remember current scanner position */
2631     int startPos = scanner.startPosition;
2632     int currentPos = scanner.currentPosition;
2633
2634     //          String[] expectings;
2635     //          String tokenName = name[symbol_index[currentKind]];
2636
2637     //fetch all "accurate" possible terminals that could recover the error
2638     //          int start, end = start = asi(stack[stateStackTop]);
2639     //          while (asr[end] != 0)
2640     //                  end++;
2641     //          int length = end - start;
2642     //          expectings = new String[length];
2643     //          if (length != 0) {
2644     //                  char[] indexes = new char[length];
2645     //                  System.arraycopy(asr, start, indexes, 0, length);
2646     //                  for (int i = 0; i < length; i++) {
2647     //                          expectings[i] = name[symbol_index[indexes[i]]];
2648     //                  }
2649     //          }
2650
2651     //if the pb is an EOF, try to tell the user that they are some 
2652     //          if (tokenName.equals(UNEXPECTED_EOF)) {
2653     //                  if (!this.checkAndReportBracketAnomalies(problemReporter())) {
2654     //                          char[] tokenSource;
2655     //                          try {
2656     //                                  tokenSource = this.scanner.getCurrentTokenSource();
2657     //                          } catch (Exception e) {
2658     //                                  tokenSource = new char[] {};
2659     //                          }
2660     //                          problemReporter().parseError(
2661     //                                  this.scanner.startPosition, 
2662     //                                  this.scanner.currentPosition - 1, 
2663     //                                  tokenSource, 
2664     //                                  tokenName, 
2665     //                                  expectings); 
2666     //                  }
2667     //          } else { //the next test is HEAVILY grammar DEPENDENT.
2668     //                  if ((length == 14)
2669     //                          && (expectings[0] == "=") //$NON-NLS-1$
2670     //                          && (expectings[1] == "*=") //$NON-NLS-1$
2671     //                          && (expressionPtr > -1)) {
2672     //                                  switch(currentKind) {
2673     //                                          case TokenNameSEMICOLON:
2674     //                                          case TokenNamePLUS:
2675     //                                          case TokenNameMINUS:
2676     //                                          case TokenNameDIVIDE:
2677     //                                          case TokenNameREMAINDER:
2678     //                                          case TokenNameMULTIPLY:
2679     //                                          case TokenNameLEFT_SHIFT:
2680     //                                          case TokenNameRIGHT_SHIFT:
2681     ////                                                case TokenNameUNSIGNED_RIGHT_SHIFT:
2682     //                                          case TokenNameLESS:
2683     //                                          case TokenNameGREATER:
2684     //                                          case TokenNameLESS_EQUAL:
2685     //                                          case TokenNameGREATER_EQUAL:
2686     //                                          case TokenNameEQUAL_EQUAL:
2687     //                                          case TokenNameNOT_EQUAL:
2688     //                                          case TokenNameXOR:
2689     //                                          case TokenNameAND:
2690     //                                          case TokenNameOR:
2691     //                                          case TokenNameOR_OR:
2692     //                                          case TokenNameAND_AND:
2693     //                                                  // the ; is not the expected token ==> it ends a statement when an expression is not ended
2694     //                                                  problemReporter().invalidExpressionAsStatement(expressionStack[expressionPtr]);
2695     //                                                  break;
2696     //                                          case TokenNameRBRACE :
2697     //                                                  problemReporter().missingSemiColon(expressionStack[expressionPtr]);
2698     //                                                  break;
2699     //                                          default:
2700     //                                                  char[] tokenSource;
2701     //                                                  try {
2702     //                                                          tokenSource = this.scanner.getCurrentTokenSource();
2703     //                                                  } catch (Exception e) {
2704     //                                                          tokenSource = new char[] {};
2705     //                                                  }
2706     //                                                  problemReporter().parseError(
2707     //                                                          this.scanner.startPosition, 
2708     //                                                          this.scanner.currentPosition - 1, 
2709     //                                                          tokenSource, 
2710     //                                                          tokenName, 
2711     //                                                          expectings); 
2712     //                                                  this.checkAndReportBracketAnomalies(problemReporter());
2713     //                                  }
2714     //                  } else {
2715     char[] tokenSource;
2716     try {
2717       tokenSource = this.scanner.getCurrentTokenSource();
2718     } catch (Exception e) {
2719       tokenSource = new char[] {
2720       };
2721     }
2722     //                          problemReporter().parseError(
2723     //                                  this.scanner.startPosition, 
2724     //                                  this.scanner.currentPosition - 1, 
2725     //                                  tokenSource, 
2726     //                                  tokenName, 
2727     //                                  expectings); 
2728     this.checkAndReportBracketAnomalies(problemReporter());
2729     //                  }
2730     //          }
2731     /* reset scanner where it was */
2732     scanner.startPosition = startPos;
2733     scanner.currentPosition = currentPos;
2734   }
2735   public static final int RoundBracket = 0;
2736   public static final int SquareBracket = 1;
2737   public static final int CurlyBracket = 2;
2738   public static final int BracketKinds = 3;
2739
2740   protected int[] nestedMethod; //the ptr is nestedType
2741   protected int nestedType, dimensions;
2742   //ast stack
2743   final static int AstStackIncrement = 100;
2744   protected int astPtr;
2745   protected AstNode[] astStack = new AstNode[AstStackIncrement];
2746   protected int astLengthPtr;
2747   protected int[] astLengthStack;
2748   AstNode[] noAstNodes = new AstNode[AstStackIncrement];
2749
2750   public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
2751   protected ReferenceContext referenceContext;
2752   protected ProblemReporter problemReporter;
2753   //  protected CompilationResult compilationResult;
2754
2755   /**
2756    * Returns this parser's problem reporter initialized with its reference context.
2757    * Also it is assumed that a problem is going to be reported, so initializes
2758    * the compilation result's line positions.
2759    */
2760   public ProblemReporter problemReporter() {
2761     if (scanner.recordLineSeparator) {
2762       compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
2763     }
2764     problemReporter.referenceContext = referenceContext;
2765     return problemReporter;
2766   }
2767   /*
2768    * Reconsider the entire source looking for inconsistencies in {} () []
2769    */
2770   public boolean checkAndReportBracketAnomalies(ProblemReporter problemReporter) {
2771
2772     scanner.wasAcr = false;
2773     boolean anomaliesDetected = false;
2774     try {
2775       char[] source = scanner.source;
2776       int[] leftCount = { 0, 0, 0 };
2777       int[] rightCount = { 0, 0, 0 };
2778       int[] depths = { 0, 0, 0 };
2779       int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10] };
2780       int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
2781       int[][] rightPositions = new int[][] { new int[10], new int[10], new int[10] };
2782       int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10] };
2783       scanner.currentPosition = scanner.initialPosition; //starting point (first-zero-based char)
2784       while (scanner.currentPosition < scanner.eofPosition) { //loop for jumping over comments
2785         try {
2786           // ---------Consume white space and handles startPosition---------
2787           boolean isWhiteSpace;
2788           do {
2789             scanner.startPosition = scanner.currentPosition;
2790             //                                          if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2791             //                                                  isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
2792             //                                          } else {
2793             if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
2794               if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
2795                 // only record line positions we have not recorded yet
2796                 scanner.pushLineSeparator();
2797               }
2798             }
2799             isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter);
2800             //                                          }
2801           } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
2802
2803           // -------consume token until } is found---------
2804
2805           switch (scanner.currentCharacter) {
2806             case '{' :
2807               {
2808                 int index = leftCount[CurlyBracket]++;
2809                 if (index == leftPositions[CurlyBracket].length) {
2810                   System.arraycopy(leftPositions[CurlyBracket], 0, (leftPositions[CurlyBracket] = new int[index * 2]), 0, index);
2811                   System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] = new int[index * 2]), 0, index);
2812                 }
2813                 leftPositions[CurlyBracket][index] = scanner.startPosition;
2814                 leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
2815               }
2816               break;
2817             case '}' :
2818               {
2819                 int index = rightCount[CurlyBracket]++;
2820                 if (index == rightPositions[CurlyBracket].length) {
2821                   System.arraycopy(rightPositions[CurlyBracket], 0, (rightPositions[CurlyBracket] = new int[index * 2]), 0, index);
2822                   System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] = new int[index * 2]), 0, index);
2823                 }
2824                 rightPositions[CurlyBracket][index] = scanner.startPosition;
2825                 rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
2826               }
2827               break;
2828             case '(' :
2829               {
2830                 int index = leftCount[RoundBracket]++;
2831                 if (index == leftPositions[RoundBracket].length) {
2832                   System.arraycopy(leftPositions[RoundBracket], 0, (leftPositions[RoundBracket] = new int[index * 2]), 0, index);
2833                   System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] = new int[index * 2]), 0, index);
2834                 }
2835                 leftPositions[RoundBracket][index] = scanner.startPosition;
2836                 leftDepths[RoundBracket][index] = depths[RoundBracket]++;
2837               }
2838               break;
2839             case ')' :
2840               {
2841                 int index = rightCount[RoundBracket]++;
2842                 if (index == rightPositions[RoundBracket].length) {
2843                   System.arraycopy(rightPositions[RoundBracket], 0, (rightPositions[RoundBracket] = new int[index * 2]), 0, index);
2844                   System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] = new int[index * 2]), 0, index);
2845                 }
2846                 rightPositions[RoundBracket][index] = scanner.startPosition;
2847                 rightDepths[RoundBracket][index] = --depths[RoundBracket];
2848               }
2849               break;
2850             case '[' :
2851               {
2852                 int index = leftCount[SquareBracket]++;
2853                 if (index == leftPositions[SquareBracket].length) {
2854                   System.arraycopy(leftPositions[SquareBracket], 0, (leftPositions[SquareBracket] = new int[index * 2]), 0, index);
2855                   System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] = new int[index * 2]), 0, index);
2856                 }
2857                 leftPositions[SquareBracket][index] = scanner.startPosition;
2858                 leftDepths[SquareBracket][index] = depths[SquareBracket]++;
2859               }
2860               break;
2861             case ']' :
2862               {
2863                 int index = rightCount[SquareBracket]++;
2864                 if (index == rightPositions[SquareBracket].length) {
2865                   System.arraycopy(rightPositions[SquareBracket], 0, (rightPositions[SquareBracket] = new int[index * 2]), 0, index);
2866                   System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket] = new int[index * 2]), 0, index);
2867                 }
2868                 rightPositions[SquareBracket][index] = scanner.startPosition;
2869                 rightDepths[SquareBracket][index] = --depths[SquareBracket];
2870               }
2871               break;
2872             case '\'' :
2873               {
2874                 if (scanner.getNextChar('\\')) {
2875                   scanner.scanEscapeCharacter();
2876                 } else { // consume next character
2877                   scanner.unicodeAsBackSlash = false;
2878                   //                                                                    if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2879                   //                                                                            scanner.getNextUnicodeChar();
2880                   //                                                                    } else {
2881                   if (scanner.withoutUnicodePtr != 0) {
2882                     scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2883                   }
2884                   //                                                                    }
2885                 }
2886                 scanner.getNextChar('\'');
2887                 break;
2888               }
2889             case '"' : // consume next character
2890               scanner.unicodeAsBackSlash = false;
2891               //                                                        if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2892               //                                                                scanner.getNextUnicodeChar();
2893               //                                                        } else {
2894               if (scanner.withoutUnicodePtr != 0) {
2895                 scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2896               }
2897               //                                                        }
2898               while (scanner.currentCharacter != '"') {
2899                 if (scanner.currentCharacter == '\r') {
2900                   if (source[scanner.currentPosition] == '\n')
2901                     scanner.currentPosition++;
2902                   break; // the string cannot go further that the line
2903                 }
2904                 if (scanner.currentCharacter == '\n') {
2905                   break; // the string cannot go further that the line
2906                 }
2907                 if (scanner.currentCharacter == '\\') {
2908                   scanner.scanEscapeCharacter();
2909                 }
2910                 // consume next character
2911                 scanner.unicodeAsBackSlash = false;
2912                 //                                                              if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2913                 //                                                                      scanner.getNextUnicodeChar();
2914                 //                                                              } else {
2915                 if (scanner.withoutUnicodePtr != 0) {
2916                   scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2917                 }
2918                 //                                                              }
2919               }
2920               break;
2921             case '/' :
2922               {
2923                 int test;
2924                 if ((test = scanner.getNextChar('/', '*')) == 0) { //line comment 
2925                   //get the next char 
2926                   if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2927                     //-------------unicode traitement ------------
2928                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2929                     scanner.currentPosition++;
2930                     while (source[scanner.currentPosition] == 'u') {
2931                       scanner.currentPosition++;
2932                     }
2933                     if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2934                       || c1 < 0
2935                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2936                       || c2 < 0
2937                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2938                       || c3 < 0
2939                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2940                       || c4 < 0) { //error don't care of the value
2941                       scanner.currentCharacter = 'A';
2942                     } //something different from \n and \r
2943                     else {
2944                       scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2945                     }
2946                   }
2947                   while (scanner.currentCharacter != '\r' && scanner.currentCharacter != '\n') {
2948                     //get the next char
2949                     scanner.startPosition = scanner.currentPosition;
2950                     if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2951                       //-------------unicode traitement ------------
2952                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2953                       scanner.currentPosition++;
2954                       while (source[scanner.currentPosition] == 'u') {
2955                         scanner.currentPosition++;
2956                       }
2957                       if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2958                         || c1 < 0
2959                         || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2960                         || c2 < 0
2961                         || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2962                         || c3 < 0
2963                         || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2964                         || c4 < 0) { //error don't care of the value
2965                         scanner.currentCharacter = 'A';
2966                       } //something different from \n and \r
2967                       else {
2968                         scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2969                       }
2970                     }
2971                   }
2972                   if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
2973                     if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
2974                       // only record line positions we have not recorded yet
2975                       scanner.pushLineSeparator();
2976                       if (this.scanner.taskTags != null) {
2977                         this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
2978                       }
2979                     }
2980                   }
2981                   break;
2982                 }
2983                 if (test > 0) { //traditional and annotation comment
2984                   boolean star = false;
2985                   // consume next character
2986                   scanner.unicodeAsBackSlash = false;
2987                   //                                                                    if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2988                   //                                                                            scanner.getNextUnicodeChar();
2989                   //                                                                    } else {
2990                   if (scanner.withoutUnicodePtr != 0) {
2991                     scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2992                   }
2993                   //                                                                    }
2994                   if (scanner.currentCharacter == '*') {
2995                     star = true;
2996                   }
2997                   //get the next char 
2998                   if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2999                     //-------------unicode traitement ------------
3000                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
3001                     scanner.currentPosition++;
3002                     while (source[scanner.currentPosition] == 'u') {
3003                       scanner.currentPosition++;
3004                     }
3005                     if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3006                       || c1 < 0
3007                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3008                       || c2 < 0
3009                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3010                       || c3 < 0
3011                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3012                       || c4 < 0) { //error don't care of the value
3013                       scanner.currentCharacter = 'A';
3014                     } //something different from * and /
3015                     else {
3016                       scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
3017                     }
3018                   }
3019                   //loop until end of comment */ 
3020                   while ((scanner.currentCharacter != '/') || (!star)) {
3021                     star = scanner.currentCharacter == '*';
3022                     //get next char
3023                     if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
3024                       //-------------unicode traitement ------------
3025                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
3026                       scanner.currentPosition++;
3027                       while (source[scanner.currentPosition] == 'u') {
3028                         scanner.currentPosition++;
3029                       }
3030                       if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3031                         || c1 < 0
3032                         || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3033                         || c2 < 0
3034                         || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3035                         || c3 < 0
3036                         || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3037                         || c4 < 0) { //error don't care of the value
3038                         scanner.currentCharacter = 'A';
3039                       } //something different from * and /
3040                       else {
3041                         scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
3042                       }
3043                     }
3044                   }
3045                   if (this.scanner.taskTags != null) {
3046                     this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
3047                   }
3048                   break;
3049                 }
3050                 break;
3051               }
3052             default :
3053               if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) {
3054                 scanner.scanIdentifierOrKeyword(false);
3055                 break;
3056               }
3057               if (Character.isDigit(scanner.currentCharacter)) {
3058                 scanner.scanNumber(false);
3059                 break;
3060               }
3061           }
3062           //-----------------end switch while try--------------------
3063         } catch (IndexOutOfBoundsException e) {
3064           break; // read until EOF
3065         } catch (InvalidInputException e) {
3066           return false; // no clue
3067         }
3068       }
3069       if (scanner.recordLineSeparator) {
3070         //                              compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
3071       }
3072
3073       // check placement anomalies against other kinds of brackets
3074       for (int kind = 0; kind < BracketKinds; kind++) {
3075         for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
3076           int start = leftPositions[kind][leftIndex]; // deepest first
3077           // find matching closing bracket
3078           int depth = leftDepths[kind][leftIndex];
3079           int end = -1;
3080           for (int i = 0; i < rightCount[kind]; i++) {
3081             int pos = rightPositions[kind][i];
3082             // want matching bracket further in source with same depth
3083             if ((pos > start) && (depth == rightDepths[kind][i])) {
3084               end = pos;
3085               break;
3086             }
3087           }
3088           if (end < 0) { // did not find a good closing match
3089             problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult);
3090             return true;
3091           }
3092           // check if even number of opening/closing other brackets in between this pair of brackets
3093           int balance = 0;
3094           for (int otherKind = 0;(balance == 0) && (otherKind < BracketKinds); otherKind++) {
3095             for (int i = 0; i < leftCount[otherKind]; i++) {
3096               int pos = leftPositions[otherKind][i];
3097               if ((pos > start) && (pos < end))
3098                 balance++;
3099             }
3100             for (int i = 0; i < rightCount[otherKind]; i++) {
3101               int pos = rightPositions[otherKind][i];
3102               if ((pos > start) && (pos < end))
3103                 balance--;
3104             }
3105             if (balance != 0) {
3106               problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult); //bracket anomaly
3107               return true;
3108             }
3109           }
3110         }
3111         // too many opening brackets ?
3112         for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
3113           anomaliesDetected = true;
3114           problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i - 1], referenceContext, compilationUnit.compilationResult);
3115         }
3116         // too many closing brackets ?
3117         for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
3118           anomaliesDetected = true;
3119           problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext, compilationUnit.compilationResult);
3120         }
3121         if (anomaliesDetected)
3122           return true;
3123       }
3124
3125       return anomaliesDetected;
3126     } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
3127       return anomaliesDetected;
3128     } catch (NullPointerException e) { // jdk1.2.2 jit bug
3129       return anomaliesDetected;
3130     }
3131   }
3132
3133   protected void pushOnAstLengthStack(int pos) {
3134     try {
3135       astLengthStack[++astLengthPtr] = pos;
3136     } catch (IndexOutOfBoundsException e) {
3137       int oldStackLength = astLengthStack.length;
3138       int[] oldPos = astLengthStack;
3139       astLengthStack = new int[oldStackLength + StackIncrement];
3140       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
3141       astLengthStack[astLengthPtr] = pos;
3142     }
3143   }
3144
3145   protected void pushOnAstStack(AstNode node) {
3146     /*add a new obj on top of the ast stack
3147     astPtr points on the top*/
3148
3149     try {
3150       astStack[++astPtr] = node;
3151     } catch (IndexOutOfBoundsException e) {
3152       int oldStackLength = astStack.length;
3153       AstNode[] oldStack = astStack;
3154       astStack = new AstNode[oldStackLength + AstStackIncrement];
3155       System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
3156       astPtr = oldStackLength;
3157       astStack[astPtr] = node;
3158     }
3159
3160     try {
3161       astLengthStack[++astLengthPtr] = 1;
3162     } catch (IndexOutOfBoundsException e) {
3163       int oldStackLength = astLengthStack.length;
3164       int[] oldPos = astLengthStack;
3165       astLengthStack = new int[oldStackLength + AstStackIncrement];
3166       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
3167       astLengthStack[astLengthPtr] = 1;
3168     }
3169   }
3170 }