no message
[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 == TokenNameAT) {
1038                 getNextToken();
1039                 if (token != TokenNamerequire
1040                                 && token != TokenNamerequire_once
1041                                 && token != TokenNameinclude
1042                                 && token != TokenNameinclude_once
1043                                 && token != TokenNameIdentifier
1044                                 && token != TokenNameVariable
1045                                 && token != TokenNamethis
1046                                 && token != TokenNameStringInterpolated) {
1047                         throwSyntaxError("identifier expected after '@'.");
1048                 }
1049         }
1050     if (token == TokenNameinclude || token == TokenNameinclude_once) {
1051       getNextToken();
1052       if (token == TokenNameLPAREN) {
1053         expression();
1054         if (token == TokenNameSEMICOLON) {
1055           getNextToken();
1056         } else {
1057           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1058             throwSyntaxError("';' expected after 'include' or 'include_once'.");
1059           }
1060           //        getNextToken();
1061         }
1062       } else {
1063         concatenationExpression();
1064       }
1065
1066       return;
1067     } else if (token == TokenNamerequire || token == TokenNamerequire_once) {
1068       getNextToken();
1069       //constant();
1070       if (token == TokenNameLPAREN) {
1071         expression();
1072         if (token == TokenNameSEMICOLON) {
1073           getNextToken();
1074         } else {
1075           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1076             throwSyntaxError("';' expected after 'require' or 'require_once'.");
1077           }
1078           //        getNextToken();
1079         }
1080       } else {
1081         concatenationExpression();
1082       }
1083       return;
1084     } else if (token == TokenNameif) {
1085       getNextToken();
1086       if (token == TokenNameLPAREN) {
1087         getNextToken();
1088       } else {
1089         throwSyntaxError("'(' expected after 'if' keyword.");
1090       }
1091       expression();
1092       if (token == TokenNameRPAREN) {
1093         getNextToken();
1094       } else {
1095         throwSyntaxError("')' expected after 'if' condition.");
1096       }
1097       ifStatement();
1098       return;
1099
1100     } else if (token == TokenNameswitch) {
1101       getNextToken();
1102       if (token == TokenNameLPAREN) {
1103         getNextToken();
1104       } else {
1105         throwSyntaxError("'(' expected after 'switch' keyword.");
1106       }
1107       expression();
1108       if (token == TokenNameRPAREN) {
1109         getNextToken();
1110       } else {
1111         throwSyntaxError("')' expected after 'switch' condition.");
1112       }
1113       switchStatement();
1114       return;
1115     } else if (token == TokenNamefor) {
1116       getNextToken();
1117       if (token == TokenNameLPAREN) {
1118         getNextToken();
1119       } else {
1120         throwSyntaxError("'(' expected after 'for' keyword.");
1121       }
1122       if (token == TokenNameSEMICOLON) {
1123         getNextToken();
1124       } else {
1125         expressionList();
1126         if (token == TokenNameSEMICOLON) {
1127           getNextToken();
1128         } else {
1129           throwSyntaxError("';' expected after 'for'.");
1130         }
1131       }
1132       if (token == TokenNameSEMICOLON) {
1133         getNextToken();
1134       } else {
1135         expressionList();
1136         if (token == TokenNameSEMICOLON) {
1137           getNextToken();
1138         } else {
1139           throwSyntaxError("';' expected after 'for'.");
1140         }
1141       }
1142       if (token == TokenNameRPAREN) {
1143         getNextToken();
1144       } else {
1145         expressionList();
1146         if (token == TokenNameRPAREN) {
1147           getNextToken();
1148         } else {
1149           throwSyntaxError("')' expected after 'for'.");
1150         }
1151       }
1152       forStatement();
1153       return;
1154     } else if (token == TokenNamewhile) {
1155       getNextToken();
1156       if (token == TokenNameLPAREN) {
1157         getNextToken();
1158       } else {
1159         throwSyntaxError("'(' expected after 'while' keyword.");
1160       }
1161       expression();
1162       if (token == TokenNameRPAREN) {
1163         getNextToken();
1164       } else {
1165         throwSyntaxError("')' expected after 'while' condition.");
1166       }
1167       whileStatement();
1168       return;
1169     } else if (token == TokenNamedo) {
1170       getNextToken();
1171       if (token == TokenNameLBRACE) {
1172         getNextToken();
1173       } else {
1174         throwSyntaxError("'{' expected after 'do' keyword.");
1175       }
1176       if (token != TokenNameRBRACE) {
1177         statementList();
1178       }
1179       if (token == TokenNameRBRACE) {
1180         getNextToken();
1181       } else {
1182         throwSyntaxError("'}' expected after 'do' keyword.");
1183       }
1184       if (token == TokenNamewhile) {
1185         getNextToken();
1186         if (token == TokenNameLPAREN) {
1187           getNextToken();
1188         } else {
1189           throwSyntaxError("'(' expected after 'while' keyword.");
1190         }
1191         expression();
1192         if (token == TokenNameRPAREN) {
1193           getNextToken();
1194         } else {
1195           throwSyntaxError("')' expected after 'while' condition.");
1196         }
1197       } else {
1198         throwSyntaxError("'while' expected after 'do' keyword.");
1199       }
1200       if (token == TokenNameSEMICOLON) {
1201         getNextToken();
1202       } else {
1203         if (token != TokenNameStopPHP) {
1204           throwSyntaxError("';' expected after do-while statement.");
1205         }
1206         getNextToken();
1207       }
1208       return;
1209     } else if (token == TokenNameforeach) {
1210       getNextToken();
1211       if (token == TokenNameLPAREN) {
1212         getNextToken();
1213       } else {
1214         throwSyntaxError("'(' expected after 'foreach' keyword.");
1215       }
1216       expression();
1217       if (token == TokenNameas) {
1218         getNextToken();
1219       } else {
1220         throwSyntaxError("'as' expected after 'foreach' exxpression.");
1221       }
1222       variable();
1223       if (token == TokenNameEQUAL_GREATER) {
1224         getNextToken();
1225         variable();
1226       }
1227       if (token == TokenNameRPAREN) {
1228         getNextToken();
1229       } else {
1230         throwSyntaxError("')' expected after 'foreach' expression.");
1231       }
1232       foreachStatement();
1233       return;
1234
1235     } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) {
1236       getNextToken();
1237       if (token != TokenNameSEMICOLON) {
1238         expression();
1239       }
1240       if (token == TokenNameSEMICOLON) {
1241         getNextToken();
1242       } else {
1243         if (token != TokenNameStopPHP) {
1244           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
1245         }
1246         getNextToken();
1247       }
1248       return;
1249
1250     } else if (token == TokenNameecho) {
1251       getNextToken();
1252       expressionList();
1253       if (token == TokenNameSEMICOLON) {
1254         getNextToken();
1255       } else {
1256         if (token != TokenNameStopPHP) {
1257           throwSyntaxError("';' expected after 'echo' statement.");
1258         }
1259         getNextToken();
1260       }
1261       return;
1262       //    } else if (token == TokenNameprint) {
1263       //      getNextToken();
1264       //      expression();
1265       //      if (token == TokenNameSEMICOLON) {
1266       //        getNextToken();
1267       //      } else {
1268       //        if (token != TokenNameStopPHP) {
1269       //          throwSyntaxError("';' expected after 'print' statement.");
1270       //        }
1271       //        getNextToken();
1272       //      }
1273       //      return;
1274
1275     } else if (token == TokenNameglobal || token == TokenNamestatic) {
1276       getNextToken();
1277       variableList();
1278       if (token == TokenNameSEMICOLON) {
1279         getNextToken();
1280       } else {
1281         if (token != TokenNameStopPHP) {
1282           throwSyntaxError("';' expected after 'global' or 'static' statement.");
1283         }
1284         getNextToken();
1285       }
1286       return;
1287
1288       //      } else if (token == TokenNameunset) {
1289       //        getNextToken();
1290       //        if (token == TokenNameARGOPEN) {
1291       //          getNextToken();
1292       //        } else {
1293       //          throwSyntaxError("'(' expected after 'unset' keyword.");
1294       //        }
1295       //        variableList();
1296       //        if (token == TokenNameARGCLOSE) {
1297       //          getNextToken();
1298       //        } else {
1299       //          throwSyntaxError("')' expected after 'unset' statement.");
1300       //        }
1301       //        if (token == TokenNameSEMICOLON) {
1302       //          getNextToken();
1303       //        } else {
1304       //          if (token != TokenNameStopPHP) {
1305       //            throwSyntaxError("';' expected after 'unset' statement.");
1306       //          }
1307       //          getNextToken();
1308       //        }
1309       //        return;
1310
1311       //      } else if (token == TokenNameexit || token == TokenNamedie) {
1312       //        getNextToken();
1313       //        if (token != TokenNameSEMICOLON) {
1314       //          exitStatus();
1315       //        }
1316       //        if (token == TokenNameSEMICOLON) {
1317       //          getNextToken();
1318       //        } else {
1319       //          if (token != TokenNameStopPHP) {
1320       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
1321       //          }
1322       //          getNextToken();
1323       //        }
1324       //        return;
1325
1326     } else if (token == TokenNamedefine) {
1327       getNextToken();
1328       if (token == TokenNameLPAREN) {
1329         getNextToken();
1330       } else {
1331         throwSyntaxError("'(' expected after 'define' keyword.");
1332       }
1333       expression();
1334       if (token == TokenNameCOMMA) {
1335         getNextToken();
1336       } else {
1337         throwSyntaxError("',' expected after first 'define' constant.");
1338       }
1339       expression();
1340       if (token == TokenNameCOMMA) {
1341         getNextToken();
1342         expression();
1343       }
1344       if (token == TokenNameRPAREN) {
1345         getNextToken();
1346       } else {
1347         throwSyntaxError("')' expected after 'define' statement.");
1348       }
1349       if (token == TokenNameSEMICOLON) {
1350         getNextToken();
1351       } else {
1352         if (token != TokenNameStopPHP) {
1353           throwSyntaxError("';' expected after 'define' statement.");
1354         }
1355         getNextToken();
1356       }
1357       return;
1358     } else if (token == TokenNamefunction) {
1359       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1360       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1361       getNextToken();
1362       functionDefinition(methodDecl);
1363       return;
1364     } else if (token == TokenNameclass) {
1365       TypeDeclaration typeDecl = new TypeDeclaration(this.compilationUnit.compilationResult);
1366       typeDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1367       // default super class
1368       typeDecl.superclass = new SingleTypeReference(TypeConstants.OBJECT, 0);
1369       compilationUnit.types.add(typeDecl);
1370       try {
1371         pushOnAstStack(typeDecl);
1372         getNextToken();
1373         classDeclarator(typeDecl);
1374         classBody(typeDecl);
1375       } finally {
1376         astPtr--;
1377         astLengthPtr--;
1378       }
1379       return;
1380       //      } else {
1381       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
1382     } else if (token == TokenNameLBRACE) {
1383       getNextToken();
1384       if (token != TokenNameRBRACE) {
1385         statementList();
1386       }
1387       if (token == TokenNameRBRACE) {
1388         getNextToken();
1389         return;
1390       } else {
1391         throwSyntaxError("'}' expected.");
1392       }
1393     } else {
1394       if (token != TokenNameSEMICOLON) {
1395         expression();
1396       }
1397       if (token == TokenNameSEMICOLON) {
1398         getNextToken();
1399         return;
1400       } else {
1401         if (token != TokenNameStopPHP && token != TokenNameEOF) {
1402           throwSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
1403         }
1404         getNextToken();
1405       }
1406     }
1407   }
1408
1409   private void classDeclarator(TypeDeclaration typeDecl) throws CoreException {
1410     //identifier
1411     //identifier 'extends' identifier
1412
1413     if (token == TokenNameIdentifier) {
1414       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1415       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1416       typeDecl.name = scanner.getCurrentIdentifierSource();
1417       getNextToken();
1418       if (token == TokenNameextends) {
1419         do {
1420           getNextToken();
1421           if (token == TokenNameIdentifier) {
1422             getNextToken();
1423           } else {
1424             reportSyntaxError("Class name expected after keyword 'extends'.", scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition());
1425             //            throwSyntaxError("ClassDeclaration name expected after keyword 'extends'.");
1426           }
1427         } while (token == TokenNameCOMMA);
1428       } 
1429     } else {
1430       typeDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1431       typeDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1432
1433       if (token > TokenNameKEYWORD) {
1434         typeDecl.name = scanner.getCurrentIdentifierSource();
1435         reportSyntaxError(
1436           "Don't use keyword for class declaration [" + scanner.toStringAction(token) + "].",
1437                                   typeDecl.sourceStart,
1438                                   typeDecl.sourceEnd);
1439         //        throwSyntaxError("Don't use keyword for class declaration [" + token + "].");
1440       }
1441       typeDecl.name = new char[] { ' ' };
1442       reportSyntaxError("Class name expected after keyword 'class'.", typeDecl.sourceStart, typeDecl.sourceEnd);
1443       //      throwSyntaxError("ClassDeclaration name expected after keyword 'class'.");
1444     }
1445   }
1446
1447   private void classBody(TypeDeclaration typeDecl) throws CoreException {
1448     //'{' [class-element-list] '}'
1449     if (token == TokenNameLBRACE) {
1450       getNextToken();
1451       if (token != TokenNameRBRACE) {
1452         classElementList();
1453       }
1454       if (token == TokenNameRBRACE) {
1455         typeDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition();
1456         getNextToken();
1457       } else {
1458         throwSyntaxError("'}' expected at end of class body.");
1459       }
1460     } else {
1461       throwSyntaxError("'{' expected at start of class body.");
1462     }
1463   }
1464
1465   private void classElementList() throws CoreException {
1466     do {
1467       classElement();
1468     } while (token == TokenNamefunction || token == TokenNamevar);
1469   }
1470
1471   private void classElement() throws CoreException {
1472     //class-property
1473     //function-definition
1474     if (token == TokenNamefunction) {
1475       MethodDeclaration methodDecl = new MethodDeclaration(this.compilationUnit.compilationResult);
1476       methodDecl.declarationSourceStart = scanner.getCurrentTokenStartPosition();
1477       getNextToken();
1478       functionDefinition(methodDecl);
1479     } else if (token == TokenNamevar) {
1480       getNextToken();
1481       classProperty();
1482     } else {
1483       throwSyntaxError("'function' or 'var' expected.");
1484     }
1485   }
1486
1487   private void classProperty() throws CoreException {
1488     //'var' variable ';'
1489     //'var' variable '=' constant ';'
1490     do {
1491       if (token == TokenNameVariable) {
1492         getNextToken();
1493         if (token == TokenNameEQUAL) {
1494           getNextToken();
1495           constant();
1496         }
1497       } else {
1498         if (token == TokenNamethis) {
1499           throwSyntaxError("Reserved word '$this' not allowed after keyword 'var'.");
1500         }
1501         throwSyntaxError("Variable expected after keyword 'var'.");
1502       }
1503       if (token != TokenNameCOMMA) {
1504         break;
1505       }
1506       getNextToken();
1507     } while (true);
1508     if (token == TokenNameSEMICOLON) {
1509       getNextToken();
1510     } else {
1511       throwSyntaxError("';' expected after variable declaration.");
1512     }
1513   }
1514
1515   private void functionDefinition(MethodDeclaration methodDecl) throws CoreException {
1516     if (astPtr == 0) {
1517       compilationUnit.types.add(methodDecl);
1518     } else {
1519       AstNode node = astStack[astPtr];
1520       if (node instanceof TypeDeclaration) {
1521         TypeDeclaration typeDecl = ((TypeDeclaration) node);
1522         if (typeDecl.methods == null) {
1523           typeDecl.methods = new AbstractMethodDeclaration[] { methodDecl };
1524         } else {
1525           AbstractMethodDeclaration[] newMethods;
1526           System.arraycopy(typeDecl.methods, 0, newMethods = new AbstractMethodDeclaration[typeDecl.methods.length + 1], 1, typeDecl.methods.length);
1527           newMethods[0] = methodDecl;
1528           typeDecl.methods = newMethods;
1529         }
1530       }
1531     }
1532     functionDeclarator(methodDecl);
1533     functionBody(methodDecl);
1534   }
1535
1536   private void functionDeclarator(MethodDeclaration methodDecl) throws CoreException {
1537     //identifier '(' [parameter-list] ')'
1538     if (token == TokenNameAND) {
1539       getNextToken();
1540     }
1541     if (token == TokenNameIdentifier) {
1542       methodDecl.sourceStart = scanner.getCurrentTokenStartPosition();
1543       methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition();
1544       methodDecl.selector = scanner.getCurrentIdentifierSource();
1545       getNextToken();
1546       if (token == TokenNameLPAREN) {
1547         getNextToken();
1548       } else {
1549         throwSyntaxError("'(' expected in function declaration.");
1550       }
1551       if (token != TokenNameRPAREN) {
1552         parameterList();
1553       }
1554       if (token != TokenNameRPAREN) {
1555         throwSyntaxError("')' expected in function declaration.");
1556       } else {
1557         methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1;
1558         getNextToken();
1559       }
1560     } else {
1561       if (token > TokenNameKEYWORD) {
1562         throwSyntaxError("Don't use keyword for function declaration [" + token + "].");
1563       }
1564       throwSyntaxError("Function name expected after keyword 'function'.");
1565     }
1566   }
1567   //
1568   private void parameterList() throws CoreException {
1569     //parameter-declaration
1570     //parameter-list ',' parameter-declaration
1571     do {
1572       parameterDeclaration();
1573       if (token != TokenNameCOMMA) {
1574         break;
1575       }
1576       getNextToken();
1577     } while (true);
1578   }
1579
1580   private void parameterDeclaration() throws CoreException {
1581     //variable
1582     //variable-reference
1583     if (token == TokenNameAND) {
1584       getNextToken();
1585       if (isVariable()) {
1586         getNextToken();
1587       } else {
1588         throwSyntaxError("Variable expected after reference operator '&'.");
1589       }
1590     }
1591     //variable '=' constant
1592     if (token == TokenNameVariable) {
1593       getNextToken();
1594       if (token == TokenNameEQUAL) {
1595         getNextToken();
1596         constant();
1597       }
1598       return;
1599     }
1600     if (token == TokenNamethis) {
1601       throwSyntaxError("Reserved word '$this' not allowed in parameter declaration.");
1602     }
1603   }
1604
1605   private void labeledStatementList() throws CoreException {
1606     if (token != TokenNamecase && token != TokenNamedefault) {
1607       throwSyntaxError("'case' or 'default' expected.");
1608     }
1609     do {
1610       if (token == TokenNamecase) {
1611         getNextToken();
1612         expression(); //constant();
1613         if (token == TokenNameCOLON) {
1614           getNextToken();
1615           if (token == TokenNamecase || token == TokenNamedefault) { // empty case statement ?
1616             continue;
1617           }
1618           statementList();
1619         } else if (token == TokenNameSEMICOLON) {
1620           //          setMarker(
1621           //            "':' expected after 'case' keyword (Found token: "
1622           //              + scanner.toStringAction(token)
1623           //              + ")",
1624           //            rowCount,
1625           //            PHPParser.INFO);
1626           setMarker(
1627             "':' expected after 'case' keyword (Found token: " + scanner.toStringAction(token) + ")",
1628             scanner.getCurrentTokenStartPosition(),
1629             scanner.getCurrentTokenEndPosition(),
1630             INFO);
1631           getNextToken();
1632           if (token == TokenNamecase) { // empty case statement ?
1633             continue;
1634           }
1635           statementList();
1636         } else {
1637           throwSyntaxError("':' character after 'case' constant expected (Found token: " + scanner.toStringAction(token) + ")");
1638         }
1639       } else { // TokenNamedefault
1640         getNextToken();
1641         if (token == TokenNameCOLON) {
1642           getNextToken();
1643           statementList();
1644         } else {
1645           throwSyntaxError("':' character after 'default' expected.");
1646         }
1647       }
1648     } while (token == TokenNamecase || token == TokenNamedefault);
1649   }
1650
1651   //  public void labeledStatement() {
1652   //    if (token == TokenNamecase) {
1653   //      getNextToken();
1654   //      constant();
1655   //      if (token == TokenNameDDOT) {
1656   //        getNextToken();
1657   //        statement();
1658   //      } else {
1659   //        throwSyntaxError("':' character after 'case' constant expected.");
1660   //      }
1661   //      return;
1662   //    } else if (token == TokenNamedefault) {
1663   //      getNextToken();
1664   //      if (token == TokenNameDDOT) {
1665   //        getNextToken();
1666   //        statement();
1667   //      } else {
1668   //        throwSyntaxError("':' character after 'default' expected.");
1669   //      }
1670   //      return;
1671   //    }
1672   //  }
1673
1674   //  public void expressionStatement() {
1675   //  }
1676
1677   //  private void inclusionStatement() {
1678   //  }
1679
1680   //  public void compoundStatement() {
1681   //  }
1682
1683   //  public void selectionStatement() {
1684   //  }
1685   //
1686   //  public void iterationStatement() {
1687   //  }
1688   //
1689   //  public void jumpStatement() {
1690   //  }
1691   //
1692   //  public void outputStatement() {
1693   //  }
1694   //
1695   //  public void scopeStatement() {
1696   //  }
1697   //
1698   //  public void flowStatement() {
1699   //  }
1700   //
1701   //  public void definitionStatement() {
1702   //  }
1703
1704   private void ifStatement() throws CoreException {
1705     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1706     if (token == TokenNameCOLON) {
1707       getNextToken();
1708       if (token != TokenNameendif) {
1709         statementList();
1710         switch (token) {
1711           case TokenNameelse :
1712             getNextToken();
1713             if (token == TokenNameCOLON) {
1714               getNextToken();
1715               if (token != TokenNameendif) {
1716                 statementList();
1717               }
1718             } else {
1719               if (token == TokenNameif) { //'else if'
1720                 getNextToken();
1721                 elseifStatementList();
1722               } else {
1723                 throwSyntaxError("':' expected after 'else'.");
1724               }
1725             }
1726             break;
1727           case TokenNameelseif :
1728             getNextToken();
1729             elseifStatementList();
1730             break;
1731         }
1732       }
1733
1734       if (token != TokenNameendif) {
1735         throwSyntaxError("'endif' expected.");
1736       }
1737       getNextToken();
1738       if (token != TokenNameSEMICOLON) {
1739         throwSyntaxError("';' expected after if-statement.");
1740       }
1741       getNextToken();
1742     } else {
1743       // statement [else-statement]
1744       statement(TokenNameEOF);
1745       if (token == TokenNameelseif) {
1746         getNextToken();
1747         if (token == TokenNameLPAREN) {
1748           getNextToken();
1749         } else {
1750           throwSyntaxError("'(' expected after 'elseif' keyword.");
1751         }
1752         expression();
1753         if (token == TokenNameRPAREN) {
1754           getNextToken();
1755         } else {
1756           throwSyntaxError("')' expected after 'elseif' condition.");
1757         }
1758         ifStatement();
1759       } else if (token == TokenNameelse) {
1760         getNextToken();
1761         statement(TokenNameEOF);
1762       }
1763     }
1764   }
1765
1766   private void elseifStatementList() throws CoreException {
1767     do {
1768       elseifStatement();
1769       switch (token) {
1770         case TokenNameelse :
1771           getNextToken();
1772           if (token == TokenNameCOLON) {
1773             getNextToken();
1774             if (token != TokenNameendif) {
1775               statementList();
1776             }
1777             return;
1778           } else {
1779             if (token == TokenNameif) { //'else if'
1780               getNextToken();
1781             } else {
1782               throwSyntaxError("':' expected after 'else'.");
1783             }
1784           }
1785           break;
1786         case TokenNameelseif :
1787           getNextToken();
1788           break;
1789         default :
1790           return;
1791       }
1792     } while (true);
1793   }
1794
1795   private void elseifStatement() throws CoreException {
1796     if (token == TokenNameLPAREN) {
1797       getNextToken();
1798       expression();
1799       if (token != TokenNameRPAREN) {
1800         throwSyntaxError("')' expected in else-if-statement.");
1801       }
1802       getNextToken();
1803       if (token != TokenNameCOLON) {
1804         throwSyntaxError("':' expected in else-if-statement.");
1805       }
1806       getNextToken();
1807       if (token != TokenNameendif) {
1808         statementList();
1809       }
1810     }
1811   }
1812
1813   private void switchStatement() throws CoreException {
1814     if (token == TokenNameCOLON) {
1815       // ':' [labeled-statement-list] 'endswitch' ';'
1816       getNextToken();
1817       labeledStatementList();
1818       if (token != TokenNameendswitch) {
1819         throwSyntaxError("'endswitch' expected.");
1820       }
1821       getNextToken();
1822       if (token != TokenNameSEMICOLON) {
1823         throwSyntaxError("';' expected after switch-statement.");
1824       }
1825       getNextToken();
1826     } else {
1827       // '{' [labeled-statement-list] '}'
1828       if (token != TokenNameLBRACE) {
1829         throwSyntaxError("'{' expected in switch statement.");
1830       }
1831       getNextToken();
1832       if (token != TokenNameRBRACE) {
1833         labeledStatementList();
1834       }
1835       if (token != TokenNameRBRACE) {
1836         throwSyntaxError("'}' expected in switch statement.");
1837       }
1838       getNextToken();
1839
1840     }
1841   }
1842
1843   private void forStatement() throws CoreException {
1844     if (token == TokenNameCOLON) {
1845       getNextToken();
1846       statementList();
1847       if (token != TokenNameendfor) {
1848         throwSyntaxError("'endfor' expected.");
1849       }
1850       getNextToken();
1851       if (token != TokenNameSEMICOLON) {
1852         throwSyntaxError("';' expected after for-statement.");
1853       }
1854       getNextToken();
1855     } else {
1856       statement(TokenNameEOF);
1857     }
1858   }
1859
1860   private void whileStatement() throws CoreException {
1861     // ':' statement-list 'endwhile' ';'
1862     if (token == TokenNameCOLON) {
1863       getNextToken();
1864       statementList();
1865       if (token != TokenNameendwhile) {
1866         throwSyntaxError("'endwhile' expected.");
1867       }
1868       getNextToken();
1869       if (token != TokenNameSEMICOLON) {
1870         throwSyntaxError("';' expected after while-statement.");
1871       }
1872       getNextToken();
1873     } else {
1874       statement(TokenNameEOF);
1875     }
1876   }
1877
1878   private void foreachStatement() throws CoreException {
1879     if (token == TokenNameCOLON) {
1880       getNextToken();
1881       statementList();
1882       if (token != TokenNameendforeach) {
1883         throwSyntaxError("'endforeach' expected.");
1884       }
1885       getNextToken();
1886       if (token != TokenNameSEMICOLON) {
1887         throwSyntaxError("';' expected after foreach-statement.");
1888       }
1889       getNextToken();
1890     } else {
1891       statement(TokenNameEOF);
1892     }
1893   }
1894
1895   private void exitStatus() throws CoreException {
1896     if (token == TokenNameLPAREN) {
1897       getNextToken();
1898     } else {
1899       throwSyntaxError("'(' expected in 'exit-status'.");
1900     }
1901     if (token != TokenNameRPAREN) {
1902       expression();
1903     }
1904     if (token == TokenNameRPAREN) {
1905       getNextToken();
1906     } else {
1907       throwSyntaxError("')' expected after 'exit-status'.");
1908     }
1909   }
1910
1911   private void expressionList() throws CoreException {
1912     do {
1913       expression();
1914       if (token == TokenNameCOMMA) {
1915         getNextToken();
1916       } else {
1917         break;
1918       }
1919     } while (true);
1920   }
1921
1922   private void expression() throws CoreException {
1923     //todo: find a better way to get the expression
1924     //    expression = new StringBuffer();
1925     //    for (int i = chIndx; i < str.length(); i++) {
1926     //      if (str.charAt(i) == ';') {
1927     //        break;
1928     //      }
1929     //      expression.append(str.charAt(i));
1930     //    }
1931
1932     //    if (token == TokenNameSTRING_CONSTANT || token == TokenNameINTERPOLATED_STRING) {
1933     //      getNextToken();
1934     //    } else {
1935     logicalinclusiveorExpression();
1936     //      while (token != TokenNameSEMICOLON) {
1937     //        getNextToken();
1938     //      //      }
1939     //    }
1940   }
1941
1942   private void postfixExpression() throws CoreException {
1943     //  String ident;
1944     char[] ident;
1945     boolean castFlag = false;
1946     boolean arrayFlag = false;
1947     switch (token) {
1948       case TokenNamenew :
1949         getNextToken();
1950         expression();
1951         break;
1952       case TokenNamenull :
1953         getNextToken();
1954         break;
1955       case TokenNamefalse :
1956         getNextToken();
1957         break;
1958       case TokenNametrue :
1959         getNextToken();
1960         break;
1961       case TokenNameStringConstant :
1962         getNextToken();
1963         break;
1964       case TokenNameHEREDOC :
1965       case TokenNameStringInterpolated :
1966       case TokenNameStringLiteral :
1967         getNextToken();
1968         break;
1969       case TokenNameLPAREN :
1970         getNextToken();
1971
1972         if (token == TokenNameIdentifier) {
1973           // check if identifier is a type:
1974           //    ident = identifier;
1975           ident = scanner.getCurrentIdentifierSource();
1976           String str = new String(ident).toLowerCase();
1977           for (int i = 0; i < PHP_TYPES.length; i++) {
1978             if (PHP_TYPES[i].equals(str)) {
1979               castFlag = true;
1980               if (PHP_TYPES[i].equals("array")) {
1981                 arrayFlag = true;
1982               }
1983               break;
1984             }
1985           }
1986         }
1987
1988         if (castFlag) {
1989           getNextToken();
1990           if (arrayFlag && token == TokenNameLPAREN) {
1991             getNextToken();
1992             if (token == TokenNameRPAREN) {
1993               getNextToken();
1994             } else {
1995               expression();
1996               if (token != TokenNameRPAREN) {
1997                 throwSyntaxError(") expected after 'array('.");
1998               }
1999             }
2000           }
2001           if (token != TokenNameRPAREN) {
2002             throwSyntaxError(") expected after cast-type '" + str + "'.");
2003           }
2004           getNextToken();
2005           expression();
2006           break;
2007         } else {
2008           expression();
2009         }
2010         if (token != TokenNameRPAREN) {
2011           throwSyntaxError(") expected in postfix-expression.");
2012         }
2013         getNextToken();
2014         break;
2015       case TokenNameDoubleLiteral :
2016         getNextToken();
2017         break;
2018       case TokenNameIntegerLiteral :
2019         getNextToken();
2020         break;
2021       case TokenNameDOLLAR_LBRACE :
2022         getNextToken();
2023         expression();
2024         if (token != TokenNameRBRACE) {
2025           throwSyntaxError("'}' expected after indirect variable token '${'.");
2026         }
2027         getNextToken();
2028         break;
2029       case TokenNameVariable :
2030       case TokenNamethis :
2031         ident = scanner.getCurrentIdentifierSource();
2032         getNextToken();
2033         if (token == TokenNameLBRACE) {
2034           getNextToken();
2035           expression();
2036           if (token != TokenNameRBRACE) {
2037             throwSyntaxError("'}' expected after variable '" + new String(ident) + "' in variable-expression.");
2038           }
2039           getNextToken();
2040         } else if (token == TokenNameLPAREN) {
2041           getNextToken();
2042           if (token != TokenNameRPAREN) {
2043             expressionList();
2044             if (token != TokenNameRPAREN) {
2045               throwSyntaxError("')' expected after variable '" + new String(ident) + "' in postfix-expression.");
2046             }
2047           }
2048           getNextToken();
2049         }
2050         break;
2051       case TokenNameIdentifier :
2052         ident = scanner.getCurrentIdentifierSource();
2053         getNextToken();
2054         if (token == TokenNameLPAREN) {
2055           getNextToken();
2056           if (token != TokenNameRPAREN) {
2057             expressionList();
2058             if (token != TokenNameRPAREN) {
2059               throwSyntaxError(
2060                 "')' expected after identifier '" + new String(ident) + "' in postfix-expression." + "(Found token: " + scanner.toStringAction(token) + ")");
2061             }
2062           }
2063           getNextToken();
2064         }
2065         break;
2066       case TokenNameprint :
2067         getNextToken();
2068         expression();
2069         //        if (token == TokenNameSEMICOLON) {
2070         //          getNextToken();
2071         //        } else {
2072         //          if (token != TokenNameStopPHP) {
2073         //            throwSyntaxError("';' expected after 'print' statement.");
2074         //          }
2075         //          getNextToken();
2076         //        }
2077         break;
2078       case TokenNamelist :
2079         getNextToken();
2080         if (token == TokenNameLPAREN) {
2081           getNextToken();
2082           if (token == TokenNameCOMMA) {
2083             getNextToken();
2084           }
2085           expressionList();
2086           if (token != TokenNameRPAREN) {
2087             throwSyntaxError("')' expected after 'list' keyword.");
2088           }
2089           getNextToken();
2090           //          if (token == TokenNameSET) {
2091           //            getNextToken();
2092           //            logicalinclusiveorExpression();
2093           //          }
2094         } else {
2095           throwSyntaxError("'(' expected after 'list' keyword.");
2096         }
2097         break;
2098         //      case TokenNameexit :
2099         //        getNextToken();
2100         //        if (token != TokenNameSEMICOLON) {
2101         //          exitStatus();
2102         //        }
2103         //        if (token == TokenNameSEMICOLON) {
2104         //          getNextToken();
2105         //        } else {
2106         //          if (token != TokenNameStopPHP) {
2107         //            throwSyntaxError("';' expected after 'exit' expression.");
2108         //          }
2109         //          getNextToken();
2110         //        }
2111         //        break;
2112         //      case TokenNamedie :
2113         //        getNextToken();
2114         //        if (token != TokenNameSEMICOLON) {
2115         //          exitStatus();
2116         //        }
2117         //        if (token == TokenNameSEMICOLON) {
2118         //          getNextToken();
2119         //        } else {
2120         //          if (token != TokenNameStopPHP) {
2121         //            throwSyntaxError("';' expected after 'die' expression.");
2122         //          }
2123         //        }
2124         //        break;
2125
2126         //      case TokenNamearray :
2127         //        getNextToken();
2128         //        if (token == TokenNameARGOPEN) {
2129         //          getNextToken();
2130         //          if (token == TokenNameCOMMA) {
2131         //            getNextToken();
2132         //          }
2133         //          expressionList();
2134         //          if (token != TokenNameARGCLOSE) {
2135         //            throwSyntaxError("')' expected after 'list' keyword.");
2136         //          }
2137         //          getNextToken();
2138         //          if (token == TokenNameSET) {
2139         //            getNextToken();
2140         //            logicalinclusiveorExpression();
2141         //          }
2142         //        } else {
2143         //          throwSyntaxError("'(' expected after 'list' keyword.");
2144         //        }
2145         //        break;
2146     }
2147     boolean while_flag = true;
2148     do {
2149       switch (token) {
2150         case TokenNameLBRACKET :
2151           getNextToken();
2152           expression();
2153           if (token != TokenNameRBRACKET) {
2154             throwSyntaxError("] expected in postfix-expression.");
2155           }
2156           getNextToken();
2157           break;
2158         case TokenNameCOLON_COLON : // ::
2159         case TokenNameMINUS_GREATER : // ->
2160           getNextToken();
2161           if (token > TokenNameKEYWORD) {
2162             ident = scanner.getCurrentIdentifierSource();
2163             //            setMarker(
2164             //              "Avoid using keyword '"
2165             //                + new String(ident)
2166             //                + "' as variable name.",
2167             //              rowCount,
2168             //              PHPParser.INFO);
2169             setMarker(
2170               "Avoid using keyword '" + new String(ident) + "' as variable name.",
2171               scanner.getCurrentTokenStartPosition(),
2172               scanner.getCurrentTokenEndPosition(),
2173               INFO);
2174           }
2175           switch (token) {
2176             case TokenNameVariable :
2177               ident = scanner.getCurrentIdentifierSource();
2178               getNextToken();
2179               //              if (token == TokenNameARGOPEN) {
2180               //                getNextToken();
2181               //                expressionList();
2182               //                if (token != TokenNameARGCLOSE) {
2183               //                  throwSyntaxError(") expected after variable '" + ident + "'.");
2184               //                }
2185               //                getNextToken();
2186               //              }
2187               break;
2188             case TokenNameIdentifier :
2189               //ident = scanner.getCurrentIdentifierSource();
2190               getNextToken();
2191               break;
2192             case TokenNameLBRACE :
2193               getNextToken();
2194               expression();
2195               if (token != TokenNameRBRACE) {
2196                 throwSyntaxError("} expected in postfix-expression.");
2197               }
2198               getNextToken();
2199               break;
2200             default :
2201               throwSyntaxError("Syntax error after '->' token.");
2202           } while (token == TokenNameLBRACKET || token == TokenNameLPAREN || token == TokenNameLBRACE) {
2203               if (token == TokenNameLBRACKET) {
2204                 getNextToken();
2205                 expressionList();
2206                 if (token != TokenNameRBRACKET) {
2207                   throwSyntaxError("] expected after '->'.");
2208                 }
2209                 getNextToken();
2210               } else if (token == TokenNameLPAREN) {
2211                 getNextToken();
2212                 expressionList();
2213                 if (token != TokenNameRPAREN) {
2214                   throwSyntaxError(") expected after '->'.");
2215                 }
2216                 getNextToken();
2217               } else if (token == TokenNameLBRACE) {
2218                 getNextToken();
2219                 expression();
2220                 if (token != TokenNameRBRACE) {
2221                   throwSyntaxError("} expected after '->'.");
2222                 }
2223                 getNextToken();
2224               }
2225             }
2226           break;
2227         case TokenNamePLUS_PLUS :
2228           getNextToken();
2229           break;
2230         case TokenNameMINUS_MINUS :
2231           getNextToken();
2232           break;
2233         default :
2234           while_flag = false;
2235       }
2236
2237     }
2238     while (while_flag);
2239   }
2240
2241   private void unaryExpression() throws CoreException {
2242     switch (token) {
2243       case TokenNamePLUS_PLUS :
2244         getNextToken();
2245         unaryExpression();
2246         break;
2247       case TokenNameMINUS_MINUS :
2248         getNextToken();
2249         unaryExpression();
2250         break;
2251         // '@' '&' '*' '+' '-' '~' '!'
2252       case TokenNameAT :
2253         getNextToken();
2254         if (token == TokenNameinclude || token == TokenNameinclude_once || token == TokenNamerequire || token == TokenNamerequire_once) {
2255           statement(TokenNameAT);
2256         } else {
2257           postfixExpression(); //  castExpression();
2258         }
2259         break;
2260       case TokenNameAND :
2261         getNextToken();
2262         castExpression();
2263         break;
2264       case TokenNameMULTIPLY :
2265         getNextToken();
2266         castExpression();
2267         break;
2268       case TokenNamePLUS :
2269         getNextToken();
2270         castExpression();
2271         break;
2272       case TokenNameMINUS :
2273         getNextToken();
2274         castExpression();
2275         break;
2276       case TokenNameTWIDDLE :
2277         getNextToken();
2278         castExpression();
2279         break;
2280       case TokenNameNOT :
2281         getNextToken();
2282         castExpression();
2283         break;
2284       default :
2285         postfixExpression();
2286     }
2287   }
2288
2289   private void castExpression() throws CoreException {
2290     //    if (token == TokenNameARGOPEN) {
2291     //      getNextToken();
2292     //      typeName();
2293     //      if (token != TokenNameARGCLOSE) {
2294     //        throwSyntaxError(") expected after cast-expression.");
2295     //      }
2296     //      getNextToken();
2297     //    }
2298     unaryExpression();
2299   }
2300
2301   private void assignExpression() throws CoreException {
2302     castExpression();
2303     if (token == TokenNameEQUAL) { // =
2304       getNextToken();
2305       logicalinclusiveorExpression();
2306     } else if (token == TokenNameDOT_EQUAL) { // .=
2307       getNextToken();
2308       logicalinclusiveorExpression();
2309     } else if (token == TokenNameEQUAL_GREATER) { // =>
2310       getNextToken();
2311       logicalinclusiveorExpression();
2312     } else if (token == TokenNamePLUS_EQUAL) { // +=
2313       getNextToken();
2314       logicalinclusiveorExpression();
2315     } else if (token == TokenNameMINUS_EQUAL) { // -=
2316       getNextToken();
2317       logicalinclusiveorExpression();
2318     } else if (token == TokenNameMULTIPLY_EQUAL) { // *=
2319       getNextToken();
2320       logicalinclusiveorExpression();
2321     } else if (token == TokenNameDIVIDE_EQUAL) { // *=
2322       getNextToken();
2323       logicalinclusiveorExpression();
2324     } else if (token == TokenNameREMAINDER_EQUAL) { // %=
2325       getNextToken();
2326       logicalinclusiveorExpression();
2327     } else if (token == TokenNameAND_EQUAL) { // &=
2328       getNextToken();
2329       logicalinclusiveorExpression();
2330     } else if (token == TokenNameOR_EQUAL) { // |=
2331       getNextToken();
2332       logicalinclusiveorExpression();
2333     } else if (token == TokenNameXOR_EQUAL) { // ^=
2334       getNextToken();
2335       logicalinclusiveorExpression();
2336     } else if (token == TokenNameLEFT_SHIFT_EQUAL) { // <<=
2337       getNextToken();
2338       logicalinclusiveorExpression();
2339     } else if (token == TokenNameRIGHT_SHIFT_EQUAL) { // >>=
2340       getNextToken();
2341       logicalinclusiveorExpression();
2342     } else if (token == TokenNameTWIDDLE_EQUAL) { // ~=
2343       getNextToken();
2344       logicalinclusiveorExpression();
2345     }
2346   }
2347
2348   private void multiplicativeExpression() throws CoreException {
2349     do {
2350       assignExpression();
2351       if (token != TokenNameMULTIPLY && token != TokenNameDIVIDE && token != TokenNameREMAINDER) {
2352         return;
2353       }
2354       getNextToken();
2355     } while (true);
2356   }
2357
2358   private void concatenationExpression() throws CoreException {
2359     do {
2360       multiplicativeExpression();
2361       if (token != TokenNameDOT) {
2362         return;
2363       }
2364       getNextToken();
2365     } while (true);
2366   }
2367
2368   private void additiveExpression() throws CoreException {
2369     do {
2370       concatenationExpression();
2371       if (token != TokenNamePLUS && token != TokenNameMINUS) {
2372         return;
2373       }
2374       getNextToken();
2375     } while (true);
2376   }
2377
2378   private void shiftExpression() throws CoreException {
2379     do {
2380       additiveExpression();
2381       if (token != TokenNameLEFT_SHIFT && token != TokenNameRIGHT_SHIFT) {
2382         return;
2383       }
2384       getNextToken();
2385     } while (true);
2386   }
2387
2388   private void relationalExpression() throws CoreException {
2389     do {
2390       shiftExpression();
2391       if (token != TokenNameLESS && token != TokenNameGREATER && token != TokenNameLESS_EQUAL && token != TokenNameGREATER_EQUAL) {
2392         return;
2393       }
2394       getNextToken();
2395     } while (true);
2396   }
2397
2398   private void identicalExpression() throws CoreException {
2399     do {
2400       relationalExpression();
2401       if (token != TokenNameEQUAL_EQUAL_EQUAL && token != TokenNameNOT_EQUAL_EQUAL) {
2402         return;
2403       }
2404       getNextToken();
2405     } while (true);
2406   }
2407
2408   private void equalityExpression() throws CoreException {
2409     do {
2410       identicalExpression();
2411       if (token != TokenNameEQUAL_EQUAL && token != TokenNameNOT_EQUAL) {
2412         return;
2413       }
2414       getNextToken();
2415     } while (true);
2416   }
2417
2418   private void ternaryExpression() throws CoreException {
2419     equalityExpression();
2420     if (token == TokenNameQUESTION) {
2421       getNextToken();
2422       expression();
2423       if (token == TokenNameCOLON) {
2424         getNextToken();
2425         expression();
2426       } else {
2427         throwSyntaxError("':' expected in ternary operator '? :'.");
2428       }
2429     }
2430   }
2431
2432   private void andExpression() throws CoreException {
2433     do {
2434       ternaryExpression();
2435       if (token != TokenNameAND) {
2436         return;
2437       }
2438       getNextToken();
2439     } while (true);
2440   }
2441
2442   private void exclusiveorExpression() throws CoreException {
2443     do {
2444       andExpression();
2445       if (token != TokenNameXOR) {
2446         return;
2447       }
2448       getNextToken();
2449     } while (true);
2450   }
2451
2452   private void inclusiveorExpression() throws CoreException {
2453     do {
2454       exclusiveorExpression();
2455       if (token != TokenNameOR) {
2456         return;
2457       }
2458       getNextToken();
2459     } while (true);
2460   }
2461
2462   private void booleanandExpression() throws CoreException {
2463     do {
2464       inclusiveorExpression();
2465       if (token != TokenNameAND_AND) {
2466         return;
2467       }
2468       getNextToken();
2469     } while (true);
2470   }
2471
2472   private void booleanorExpression() throws CoreException {
2473     do {
2474       booleanandExpression();
2475       if (token != TokenNameOR_OR) {
2476         return;
2477       }
2478       getNextToken();
2479     } while (true);
2480   }
2481
2482   private void logicalandExpression() throws CoreException {
2483     do {
2484       booleanorExpression();
2485       if (token != TokenNameAND) {
2486         return;
2487       }
2488       getNextToken();
2489     } while (true);
2490   }
2491
2492   private void logicalexclusiveorExpression() throws CoreException {
2493     do {
2494       logicalandExpression();
2495       if (token != TokenNameXOR) {
2496         return;
2497       }
2498       getNextToken();
2499     } while (true);
2500   }
2501
2502   private void logicalinclusiveorExpression() throws CoreException {
2503     do {
2504       logicalexclusiveorExpression();
2505       if (token != TokenNameOR) {
2506         return;
2507       }
2508       getNextToken();
2509     } while (true);
2510   }
2511
2512   //  public void assignmentExpression() {
2513   //    if (token == TokenNameVARIABLE) {
2514   //      getNextToken();
2515   //      if (token == TokenNameSET) {
2516   //        getNextToken();
2517   //        logicalinclusiveorExpression();
2518   //      }
2519   //    } else {
2520   //      logicalinclusiveorExpression();
2521   //    }
2522   //  }
2523
2524   private void variableList() throws CoreException {
2525     do {
2526       variable();
2527       if (token == TokenNameCOMMA) {
2528         getNextToken();
2529       } else {
2530         break;
2531       }
2532     } while (true);
2533   }
2534
2535   private void variable() throws CoreException {
2536     if (token == TokenNameDOLLAR_LBRACE) {
2537       getNextToken();
2538       expression();
2539       ;
2540       if (token != TokenNameRBRACE) {
2541         throwSyntaxError("'}' expected after indirect variable token '${'.");
2542       }
2543       getNextToken();
2544     } else {
2545       if (token == TokenNameVariable) {
2546         getNextToken();
2547         if (token == TokenNameLBRACKET) {
2548           getNextToken();
2549           expression();
2550           if (token != TokenNameRBRACKET) {
2551             throwSyntaxError("']' expected in variable-list.");
2552           }
2553           getNextToken();
2554         } else if (token == TokenNameEQUAL) {
2555           getNextToken();
2556           constant();
2557         }
2558       } else {
2559         throwSyntaxError("$-variable expected in variable-list.");
2560       }
2561     }
2562   }
2563
2564   /**
2565    * It will look for a value (after a '=' for example)
2566    * @throws CoreException
2567    */
2568   private void constant() throws CoreException {
2569     //   String ident;
2570     switch (token) {
2571       case TokenNamePLUS :
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 TokenNameMINUS :
2585         getNextToken();
2586         switch (token) {
2587           case TokenNameDoubleLiteral :
2588             getNextToken();
2589             break;
2590           case TokenNameIntegerLiteral :
2591             getNextToken();
2592             break;
2593           default :
2594             throwSyntaxError("Constant expected after '-' presign.");
2595         }
2596         break;
2597       case TokenNamenull :
2598         getNextToken();
2599         break;
2600       case TokenNamefalse :
2601         getNextToken();
2602         break;
2603       case TokenNametrue :
2604         getNextToken();
2605         break;
2606       case TokenNameIdentifier :
2607         //   ident = identifier;
2608         char[] ident = scanner.getCurrentIdentifierSource();
2609         getNextToken();
2610         if (token == TokenNameLPAREN) {
2611           getNextToken();
2612           if (token != TokenNameRPAREN) {
2613             expressionList();
2614             if (token != TokenNameRPAREN) {
2615               throwSyntaxError("')' expected after identifier '" + new String(ident) + "' in postfix-expression.");
2616             }
2617           }
2618           getNextToken();
2619         }
2620         break;
2621       case TokenNameStringLiteral :
2622         getNextToken();
2623         break;
2624       case TokenNameStringConstant :
2625         getNextToken();
2626         break;
2627       case TokenNameStringInterpolated :
2628         getNextToken();
2629         break;
2630       case TokenNameDoubleLiteral :
2631         getNextToken();
2632         break;
2633       case TokenNameIntegerLiteral :
2634         getNextToken();
2635         break;
2636       default :
2637         throwSyntaxError("Constant expected.");
2638     }
2639   }
2640
2641   public void reportSyntaxError() { //int act, int currentKind, int stateStackTop) {
2642
2643     /* remember current scanner position */
2644     int startPos = scanner.startPosition;
2645     int currentPos = scanner.currentPosition;
2646
2647     //          String[] expectings;
2648     //          String tokenName = name[symbol_index[currentKind]];
2649
2650     //fetch all "accurate" possible terminals that could recover the error
2651     //          int start, end = start = asi(stack[stateStackTop]);
2652     //          while (asr[end] != 0)
2653     //                  end++;
2654     //          int length = end - start;
2655     //          expectings = new String[length];
2656     //          if (length != 0) {
2657     //                  char[] indexes = new char[length];
2658     //                  System.arraycopy(asr, start, indexes, 0, length);
2659     //                  for (int i = 0; i < length; i++) {
2660     //                          expectings[i] = name[symbol_index[indexes[i]]];
2661     //                  }
2662     //          }
2663
2664     //if the pb is an EOF, try to tell the user that they are some 
2665     //          if (tokenName.equals(UNEXPECTED_EOF)) {
2666     //                  if (!this.checkAndReportBracketAnomalies(problemReporter())) {
2667     //                          char[] tokenSource;
2668     //                          try {
2669     //                                  tokenSource = this.scanner.getCurrentTokenSource();
2670     //                          } catch (Exception e) {
2671     //                                  tokenSource = new char[] {};
2672     //                          }
2673     //                          problemReporter().parseError(
2674     //                                  this.scanner.startPosition, 
2675     //                                  this.scanner.currentPosition - 1, 
2676     //                                  tokenSource, 
2677     //                                  tokenName, 
2678     //                                  expectings); 
2679     //                  }
2680     //          } else { //the next test is HEAVILY grammar DEPENDENT.
2681     //                  if ((length == 14)
2682     //                          && (expectings[0] == "=") //$NON-NLS-1$
2683     //                          && (expectings[1] == "*=") //$NON-NLS-1$
2684     //                          && (expressionPtr > -1)) {
2685     //                                  switch(currentKind) {
2686     //                                          case TokenNameSEMICOLON:
2687     //                                          case TokenNamePLUS:
2688     //                                          case TokenNameMINUS:
2689     //                                          case TokenNameDIVIDE:
2690     //                                          case TokenNameREMAINDER:
2691     //                                          case TokenNameMULTIPLY:
2692     //                                          case TokenNameLEFT_SHIFT:
2693     //                                          case TokenNameRIGHT_SHIFT:
2694     ////                                                case TokenNameUNSIGNED_RIGHT_SHIFT:
2695     //                                          case TokenNameLESS:
2696     //                                          case TokenNameGREATER:
2697     //                                          case TokenNameLESS_EQUAL:
2698     //                                          case TokenNameGREATER_EQUAL:
2699     //                                          case TokenNameEQUAL_EQUAL:
2700     //                                          case TokenNameNOT_EQUAL:
2701     //                                          case TokenNameXOR:
2702     //                                          case TokenNameAND:
2703     //                                          case TokenNameOR:
2704     //                                          case TokenNameOR_OR:
2705     //                                          case TokenNameAND_AND:
2706     //                                                  // the ; is not the expected token ==> it ends a statement when an expression is not ended
2707     //                                                  problemReporter().invalidExpressionAsStatement(expressionStack[expressionPtr]);
2708     //                                                  break;
2709     //                                          case TokenNameRBRACE :
2710     //                                                  problemReporter().missingSemiColon(expressionStack[expressionPtr]);
2711     //                                                  break;
2712     //                                          default:
2713     //                                                  char[] tokenSource;
2714     //                                                  try {
2715     //                                                          tokenSource = this.scanner.getCurrentTokenSource();
2716     //                                                  } catch (Exception e) {
2717     //                                                          tokenSource = new char[] {};
2718     //                                                  }
2719     //                                                  problemReporter().parseError(
2720     //                                                          this.scanner.startPosition, 
2721     //                                                          this.scanner.currentPosition - 1, 
2722     //                                                          tokenSource, 
2723     //                                                          tokenName, 
2724     //                                                          expectings); 
2725     //                                                  this.checkAndReportBracketAnomalies(problemReporter());
2726     //                                  }
2727     //                  } else {
2728     char[] tokenSource;
2729     try {
2730       tokenSource = this.scanner.getCurrentTokenSource();
2731     } catch (Exception e) {
2732       tokenSource = new char[] {
2733       };
2734     }
2735     //                          problemReporter().parseError(
2736     //                                  this.scanner.startPosition, 
2737     //                                  this.scanner.currentPosition - 1, 
2738     //                                  tokenSource, 
2739     //                                  tokenName, 
2740     //                                  expectings); 
2741     this.checkAndReportBracketAnomalies(problemReporter());
2742     //                  }
2743     //          }
2744     /* reset scanner where it was */
2745     scanner.startPosition = startPos;
2746     scanner.currentPosition = currentPos;
2747   }
2748   public static final int RoundBracket = 0;
2749   public static final int SquareBracket = 1;
2750   public static final int CurlyBracket = 2;
2751   public static final int BracketKinds = 3;
2752
2753   protected int[] nestedMethod; //the ptr is nestedType
2754   protected int nestedType, dimensions;
2755   //ast stack
2756   final static int AstStackIncrement = 100;
2757   protected int astPtr;
2758   protected AstNode[] astStack = new AstNode[AstStackIncrement];
2759   protected int astLengthPtr;
2760   protected int[] astLengthStack;
2761   AstNode[] noAstNodes = new AstNode[AstStackIncrement];
2762
2763   public CompilationUnitDeclaration compilationUnit; /*the result from parse()*/
2764   protected ReferenceContext referenceContext;
2765   protected ProblemReporter problemReporter;
2766   //  protected CompilationResult compilationResult;
2767
2768   /**
2769    * Returns this parser's problem reporter initialized with its reference context.
2770    * Also it is assumed that a problem is going to be reported, so initializes
2771    * the compilation result's line positions.
2772    */
2773   public ProblemReporter problemReporter() {
2774     if (scanner.recordLineSeparator) {
2775       compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
2776     }
2777     problemReporter.referenceContext = referenceContext;
2778     return problemReporter;
2779   }
2780   /*
2781    * Reconsider the entire source looking for inconsistencies in {} () []
2782    */
2783   public boolean checkAndReportBracketAnomalies(ProblemReporter problemReporter) {
2784
2785     scanner.wasAcr = false;
2786     boolean anomaliesDetected = false;
2787     try {
2788       char[] source = scanner.source;
2789       int[] leftCount = { 0, 0, 0 };
2790       int[] rightCount = { 0, 0, 0 };
2791       int[] depths = { 0, 0, 0 };
2792       int[][] leftPositions = new int[][] { new int[10], new int[10], new int[10] };
2793       int[][] leftDepths = new int[][] { new int[10], new int[10], new int[10] };
2794       int[][] rightPositions = new int[][] { new int[10], new int[10], new int[10] };
2795       int[][] rightDepths = new int[][] { new int[10], new int[10], new int[10] };
2796       scanner.currentPosition = scanner.initialPosition; //starting point (first-zero-based char)
2797       while (scanner.currentPosition < scanner.eofPosition) { //loop for jumping over comments
2798         try {
2799           // ---------Consume white space and handles startPosition---------
2800           boolean isWhiteSpace;
2801           do {
2802             scanner.startPosition = scanner.currentPosition;
2803             //                                          if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2804             //                                                  isWhiteSpace = scanner.jumpOverUnicodeWhiteSpace();
2805             //                                          } else {
2806             if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
2807               if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
2808                 // only record line positions we have not recorded yet
2809                 scanner.pushLineSeparator();
2810               }
2811             }
2812             isWhiteSpace = CharOperation.isWhitespace(scanner.currentCharacter);
2813             //                                          }
2814           } while (isWhiteSpace && (scanner.currentPosition < scanner.eofPosition));
2815
2816           // -------consume token until } is found---------
2817
2818           switch (scanner.currentCharacter) {
2819             case '{' :
2820               {
2821                 int index = leftCount[CurlyBracket]++;
2822                 if (index == leftPositions[CurlyBracket].length) {
2823                   System.arraycopy(leftPositions[CurlyBracket], 0, (leftPositions[CurlyBracket] = new int[index * 2]), 0, index);
2824                   System.arraycopy(leftDepths[CurlyBracket], 0, (leftDepths[CurlyBracket] = new int[index * 2]), 0, index);
2825                 }
2826                 leftPositions[CurlyBracket][index] = scanner.startPosition;
2827                 leftDepths[CurlyBracket][index] = depths[CurlyBracket]++;
2828               }
2829               break;
2830             case '}' :
2831               {
2832                 int index = rightCount[CurlyBracket]++;
2833                 if (index == rightPositions[CurlyBracket].length) {
2834                   System.arraycopy(rightPositions[CurlyBracket], 0, (rightPositions[CurlyBracket] = new int[index * 2]), 0, index);
2835                   System.arraycopy(rightDepths[CurlyBracket], 0, (rightDepths[CurlyBracket] = new int[index * 2]), 0, index);
2836                 }
2837                 rightPositions[CurlyBracket][index] = scanner.startPosition;
2838                 rightDepths[CurlyBracket][index] = --depths[CurlyBracket];
2839               }
2840               break;
2841             case '(' :
2842               {
2843                 int index = leftCount[RoundBracket]++;
2844                 if (index == leftPositions[RoundBracket].length) {
2845                   System.arraycopy(leftPositions[RoundBracket], 0, (leftPositions[RoundBracket] = new int[index * 2]), 0, index);
2846                   System.arraycopy(leftDepths[RoundBracket], 0, (leftDepths[RoundBracket] = new int[index * 2]), 0, index);
2847                 }
2848                 leftPositions[RoundBracket][index] = scanner.startPosition;
2849                 leftDepths[RoundBracket][index] = depths[RoundBracket]++;
2850               }
2851               break;
2852             case ')' :
2853               {
2854                 int index = rightCount[RoundBracket]++;
2855                 if (index == rightPositions[RoundBracket].length) {
2856                   System.arraycopy(rightPositions[RoundBracket], 0, (rightPositions[RoundBracket] = new int[index * 2]), 0, index);
2857                   System.arraycopy(rightDepths[RoundBracket], 0, (rightDepths[RoundBracket] = new int[index * 2]), 0, index);
2858                 }
2859                 rightPositions[RoundBracket][index] = scanner.startPosition;
2860                 rightDepths[RoundBracket][index] = --depths[RoundBracket];
2861               }
2862               break;
2863             case '[' :
2864               {
2865                 int index = leftCount[SquareBracket]++;
2866                 if (index == leftPositions[SquareBracket].length) {
2867                   System.arraycopy(leftPositions[SquareBracket], 0, (leftPositions[SquareBracket] = new int[index * 2]), 0, index);
2868                   System.arraycopy(leftDepths[SquareBracket], 0, (leftDepths[SquareBracket] = new int[index * 2]), 0, index);
2869                 }
2870                 leftPositions[SquareBracket][index] = scanner.startPosition;
2871                 leftDepths[SquareBracket][index] = depths[SquareBracket]++;
2872               }
2873               break;
2874             case ']' :
2875               {
2876                 int index = rightCount[SquareBracket]++;
2877                 if (index == rightPositions[SquareBracket].length) {
2878                   System.arraycopy(rightPositions[SquareBracket], 0, (rightPositions[SquareBracket] = new int[index * 2]), 0, index);
2879                   System.arraycopy(rightDepths[SquareBracket], 0, (rightDepths[SquareBracket] = new int[index * 2]), 0, index);
2880                 }
2881                 rightPositions[SquareBracket][index] = scanner.startPosition;
2882                 rightDepths[SquareBracket][index] = --depths[SquareBracket];
2883               }
2884               break;
2885             case '\'' :
2886               {
2887                 if (scanner.getNextChar('\\')) {
2888                   scanner.scanEscapeCharacter();
2889                 } else { // 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                 }
2899                 scanner.getNextChar('\'');
2900                 break;
2901               }
2902             case '"' : // consume next character
2903               scanner.unicodeAsBackSlash = false;
2904               //                                                        if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2905               //                                                                scanner.getNextUnicodeChar();
2906               //                                                        } else {
2907               if (scanner.withoutUnicodePtr != 0) {
2908                 scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2909               }
2910               //                                                        }
2911               while (scanner.currentCharacter != '"') {
2912                 if (scanner.currentCharacter == '\r') {
2913                   if (source[scanner.currentPosition] == '\n')
2914                     scanner.currentPosition++;
2915                   break; // the string cannot go further that the line
2916                 }
2917                 if (scanner.currentCharacter == '\n') {
2918                   break; // the string cannot go further that the line
2919                 }
2920                 if (scanner.currentCharacter == '\\') {
2921                   scanner.scanEscapeCharacter();
2922                 }
2923                 // consume next character
2924                 scanner.unicodeAsBackSlash = false;
2925                 //                                                              if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2926                 //                                                                      scanner.getNextUnicodeChar();
2927                 //                                                              } else {
2928                 if (scanner.withoutUnicodePtr != 0) {
2929                   scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
2930                 }
2931                 //                                                              }
2932               }
2933               break;
2934             case '/' :
2935               {
2936                 int test;
2937                 if ((test = scanner.getNextChar('/', '*')) == 0) { //line comment 
2938                   //get the next char 
2939                   if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2940                     //-------------unicode traitement ------------
2941                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2942                     scanner.currentPosition++;
2943                     while (source[scanner.currentPosition] == 'u') {
2944                       scanner.currentPosition++;
2945                     }
2946                     if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2947                       || c1 < 0
2948                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2949                       || c2 < 0
2950                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2951                       || c3 < 0
2952                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2953                       || c4 < 0) { //error don't care of the value
2954                       scanner.currentCharacter = 'A';
2955                     } //something different from \n and \r
2956                     else {
2957                       scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2958                     }
2959                   }
2960                   while (scanner.currentCharacter != '\r' && scanner.currentCharacter != '\n') {
2961                     //get the next char
2962                     scanner.startPosition = scanner.currentPosition;
2963                     if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
2964                       //-------------unicode traitement ------------
2965                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
2966                       scanner.currentPosition++;
2967                       while (source[scanner.currentPosition] == 'u') {
2968                         scanner.currentPosition++;
2969                       }
2970                       if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2971                         || c1 < 0
2972                         || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2973                         || c2 < 0
2974                         || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2975                         || c3 < 0
2976                         || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
2977                         || c4 < 0) { //error don't care of the value
2978                         scanner.currentCharacter = 'A';
2979                       } //something different from \n and \r
2980                       else {
2981                         scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
2982                       }
2983                     }
2984                   }
2985                   if (scanner.recordLineSeparator && ((scanner.currentCharacter == '\r') || (scanner.currentCharacter == '\n'))) {
2986                     if (scanner.lineEnds[scanner.linePtr] < scanner.startPosition) {
2987                       // only record line positions we have not recorded yet
2988                       scanner.pushLineSeparator();
2989                       if (this.scanner.taskTags != null) {
2990                         this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
2991                       }
2992                     }
2993                   }
2994                   break;
2995                 }
2996                 if (test > 0) { //traditional and annotation comment
2997                   boolean star = false;
2998                   // consume next character
2999                   scanner.unicodeAsBackSlash = false;
3000                   //                                                                    if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
3001                   //                                                                            scanner.getNextUnicodeChar();
3002                   //                                                                    } else {
3003                   if (scanner.withoutUnicodePtr != 0) {
3004                     scanner.withoutUnicodeBuffer[++scanner.withoutUnicodePtr] = scanner.currentCharacter;
3005                   }
3006                   //                                                                    }
3007                   if (scanner.currentCharacter == '*') {
3008                     star = true;
3009                   }
3010                   //get the next char 
3011                   if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
3012                     //-------------unicode traitement ------------
3013                     int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
3014                     scanner.currentPosition++;
3015                     while (source[scanner.currentPosition] == 'u') {
3016                       scanner.currentPosition++;
3017                     }
3018                     if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3019                       || c1 < 0
3020                       || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3021                       || c2 < 0
3022                       || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3023                       || c3 < 0
3024                       || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3025                       || c4 < 0) { //error don't care of the value
3026                       scanner.currentCharacter = 'A';
3027                     } //something different from * and /
3028                     else {
3029                       scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
3030                     }
3031                   }
3032                   //loop until end of comment */ 
3033                   while ((scanner.currentCharacter != '/') || (!star)) {
3034                     star = scanner.currentCharacter == '*';
3035                     //get next char
3036                     if (((scanner.currentCharacter = source[scanner.currentPosition++]) == '\\') && (source[scanner.currentPosition] == 'u')) {
3037                       //-------------unicode traitement ------------
3038                       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
3039                       scanner.currentPosition++;
3040                       while (source[scanner.currentPosition] == 'u') {
3041                         scanner.currentPosition++;
3042                       }
3043                       if ((c1 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3044                         || c1 < 0
3045                         || (c2 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3046                         || c2 < 0
3047                         || (c3 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3048                         || c3 < 0
3049                         || (c4 = Character.getNumericValue(source[scanner.currentPosition++])) > 15
3050                         || c4 < 0) { //error don't care of the value
3051                         scanner.currentCharacter = 'A';
3052                       } //something different from * and /
3053                       else {
3054                         scanner.currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4);
3055                       }
3056                     }
3057                   }
3058                   if (this.scanner.taskTags != null) {
3059                     this.scanner.checkTaskTag(this.scanner.getCurrentTokenStartPosition(), this.scanner.getCurrentTokenEndPosition());
3060                   }
3061                   break;
3062                 }
3063                 break;
3064               }
3065             default :
3066               if (Scanner.isPHPIdentifierStart(scanner.currentCharacter)) {
3067                 scanner.scanIdentifierOrKeyword(false);
3068                 break;
3069               }
3070               if (Character.isDigit(scanner.currentCharacter)) {
3071                 scanner.scanNumber(false);
3072                 break;
3073               }
3074           }
3075           //-----------------end switch while try--------------------
3076         } catch (IndexOutOfBoundsException e) {
3077           break; // read until EOF
3078         } catch (InvalidInputException e) {
3079           return false; // no clue
3080         }
3081       }
3082       if (scanner.recordLineSeparator) {
3083         //                              compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds();
3084       }
3085
3086       // check placement anomalies against other kinds of brackets
3087       for (int kind = 0; kind < BracketKinds; kind++) {
3088         for (int leftIndex = leftCount[kind] - 1; leftIndex >= 0; leftIndex--) {
3089           int start = leftPositions[kind][leftIndex]; // deepest first
3090           // find matching closing bracket
3091           int depth = leftDepths[kind][leftIndex];
3092           int end = -1;
3093           for (int i = 0; i < rightCount[kind]; i++) {
3094             int pos = rightPositions[kind][i];
3095             // want matching bracket further in source with same depth
3096             if ((pos > start) && (depth == rightDepths[kind][i])) {
3097               end = pos;
3098               break;
3099             }
3100           }
3101           if (end < 0) { // did not find a good closing match
3102             problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult);
3103             return true;
3104           }
3105           // check if even number of opening/closing other brackets in between this pair of brackets
3106           int balance = 0;
3107           for (int otherKind = 0;(balance == 0) && (otherKind < BracketKinds); otherKind++) {
3108             for (int i = 0; i < leftCount[otherKind]; i++) {
3109               int pos = leftPositions[otherKind][i];
3110               if ((pos > start) && (pos < end))
3111                 balance++;
3112             }
3113             for (int i = 0; i < rightCount[otherKind]; i++) {
3114               int pos = rightPositions[otherKind][i];
3115               if ((pos > start) && (pos < end))
3116                 balance--;
3117             }
3118             if (balance != 0) {
3119               problemReporter.unmatchedBracket(start, referenceContext, compilationUnit.compilationResult); //bracket anomaly
3120               return true;
3121             }
3122           }
3123         }
3124         // too many opening brackets ?
3125         for (int i = rightCount[kind]; i < leftCount[kind]; i++) {
3126           anomaliesDetected = true;
3127           problemReporter.unmatchedBracket(leftPositions[kind][leftCount[kind] - i - 1], referenceContext, compilationUnit.compilationResult);
3128         }
3129         // too many closing brackets ?
3130         for (int i = leftCount[kind]; i < rightCount[kind]; i++) {
3131           anomaliesDetected = true;
3132           problemReporter.unmatchedBracket(rightPositions[kind][i], referenceContext, compilationUnit.compilationResult);
3133         }
3134         if (anomaliesDetected)
3135           return true;
3136       }
3137
3138       return anomaliesDetected;
3139     } catch (ArrayStoreException e) { // jdk1.2.2 jit bug
3140       return anomaliesDetected;
3141     } catch (NullPointerException e) { // jdk1.2.2 jit bug
3142       return anomaliesDetected;
3143     }
3144   }
3145
3146   protected void pushOnAstLengthStack(int pos) {
3147     try {
3148       astLengthStack[++astLengthPtr] = pos;
3149     } catch (IndexOutOfBoundsException e) {
3150       int oldStackLength = astLengthStack.length;
3151       int[] oldPos = astLengthStack;
3152       astLengthStack = new int[oldStackLength + StackIncrement];
3153       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
3154       astLengthStack[astLengthPtr] = pos;
3155     }
3156   }
3157
3158   protected void pushOnAstStack(AstNode node) {
3159     /*add a new obj on top of the ast stack
3160     astPtr points on the top*/
3161
3162     try {
3163       astStack[++astPtr] = node;
3164     } catch (IndexOutOfBoundsException e) {
3165       int oldStackLength = astStack.length;
3166       AstNode[] oldStack = astStack;
3167       astStack = new AstNode[oldStackLength + AstStackIncrement];
3168       System.arraycopy(oldStack, 0, astStack, 0, oldStackLength);
3169       astPtr = oldStackLength;
3170       astStack[astPtr] = node;
3171     }
3172
3173     try {
3174       astLengthStack[++astLengthPtr] = 1;
3175     } catch (IndexOutOfBoundsException e) {
3176       int oldStackLength = astLengthStack.length;
3177       int[] oldPos = astLengthStack;
3178       astLengthStack = new int[oldStackLength + AstStackIncrement];
3179       System.arraycopy(oldPos, 0, astLengthStack, 0, oldStackLength);
3180       astLengthStack[astLengthPtr] = 1;
3181     }
3182   }
3183 }