fixed parser bug;
[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.ITerminalSymbols;
16 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
17 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
18 import net.sourceforge.phpeclipse.phpeditor.PHPString;
19
20 import org.eclipse.core.resources.IFile;
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.jface.preference.IPreferenceStore;
23
24 import test.PHPParserSuperclass;
25
26 public class Parser extends PHPParserSuperclass implements ITerminalSymbols {
27
28   //scanner token
29   public Scanner scanner;
30
31   private ArrayList phpList;
32
33   private int currentPHPString;
34   private boolean phpEnd;
35
36   // private static HashMap keywordMap = null;
37   private String str;
38
39   // current character
40   //  char ch;
41   // current token
42   int token;
43
44   // row counter for syntax errors:
45   //int rowCount;
46   // column counter for syntax errors:
47   //int columnCount;
48
49   //int chIndx;
50   //
51   //    // current identifier
52   //    String identifier;
53
54   Long longNumber;
55   Double doubleNumber;
56
57   private String stringValue;
58
59   /** Contains the current expression. */
60   // private StringBuffer expression;
61
62   private boolean phpMode;
63
64   //    final static int TokenNameEOF = 0;
65   //    final static int TokenNameERROR = 1;
66   //    final static int TokenNameHTML = 2;
67   //
68   //    final static int TokenNameREMAINDER = 30;
69   //    final static int TokenNameNOT = 31;
70   //    final static int TokenNameDOT = 32;
71   //    final static int TokenNameXOR = 33;
72   //    final static int TokenNameDIVIDE = 34;
73   //    final static int TokenNameMULTIPLY = 35;
74   //    final static int TokenNameMINUS = 36;
75   //    final static int TokenNamePLUS = 37;
76   //    final static int TokenNameEQUAL_EQUAL = 38;
77   //    final static int TokenNameNOT_EQUAL = 39;
78   //    final static int TokenNameGREATER = 40;
79   //    final static int TokenNameGREATER_EQUAL = 41;
80   //    final static int TokenNameLESS = 42;
81   //    final static int TokenNameLESS_EQUAL = 43;
82   //    final static int TokenNameAND_AND = 44;
83   //    final static int TokenNameOR_OR = 45;
84   //    // final static int TokenNameHASH = 46; 
85   //    final static int TokenNameCOLON = 47;
86   //    final static int TokenNameDOT_EQUAL = 48;
87   //
88   //    final static int TokenNameEQUAL = 49;
89   //    final static int TokenNameMINUS_GREATER = 50; // ->
90   //    final static int TokenNameFOREACH = 51;
91   //    final static int TokenNameAND = 52;
92   //    //final static int TokenNameDOLLARLISTOPEN = 53;
93   //    final static int TokenNameTWIDDLE = 54;
94   //    final static int TokenNameTWIDDLE_EQUAL = 55;
95   //    final static int TokenNameREMAINDER_EQUAL = 56;
96   //    final static int TokenNameXOR_EQUAL = 57;
97   //    final static int TokenNameRIGHT_SHIFT_EQUAL = 58;
98   //    final static int TokenNameLEFT_SHIFT_EQUAL = 59;
99   //    final static int TokenNameAND_EQUAL = 60;
100   //    final static int TokenNameOR_EQUAL = 61;
101   //    final static int TokenNameQUESTION = 62;
102   //    final static int TokenNameCOLON_COLON = 63;
103   //    final static int TokenNameAT = 63;
104   //    // final static int TokenNameHEREDOC = 64;
105   //
106   //    final static int TokenNameDOLLAROPEN = 127;
107   //    final static int TokenNameLPAREN = 128;
108   //    final static int TokenNameRPAREN = 129;
109   //    final static int TokenNameLBRACE = 130;
110   //    final static int TokenNameRBRACE = 131;
111   //    final static int TokenNameLBRACKET = 132;
112   //    final static int TokenNameRBRACKET = 133;
113   //    final static int TokenNameCOMMA = 134;
114   //
115   //    final static int TokenNameStringLiteral = 136;
116   //    final static int TokenNameIdentifier = 138;
117   //    // final static int TokenNameDIGIT = 139;
118   //    final static int TokenNameSEMICOLON = 140;
119   //    // final static int TokenNameSLOT = 141;
120   //    // final static int TokenNameSLOTSEQUENCE = 142;
121   //    final static int TokenNameMINUS_MINUS = 144;
122   //    final static int TokenNamePLUS_PLUS = 145;
123   //    final static int TokenNamePLUS_EQUAL = 146;
124   //    final static int TokenNameDIVIDE_EQUAL = 147;
125   //    final static int TokenNameMINUS_EQUAL = 148;
126   //    final static int TokenNameMULTIPLY_EQUAL = 149;
127   //    final static int TokenNameVariable = 150;
128   //    final static int TokenNameIntegerLiteral = 151;
129   //    final static int TokenNameDoubleLiteral = 152;
130   //    final static int TokenNameStringInterpolated = 153;
131   //    final static int TokenNameStringConstant = 154;
132   //
133   //    final static int TokenNameLEFT_SHIFT = 155;
134   //    final static int TokenNameRIGHT_SHIFT = 156;
135   //    final static int TokenNameEQUAL_EQUAL_EQUAL = 157;
136   //    final static int TokenNameNOT_EQUAL_EQUAL = 158;
137   //    final static int TokenNameOR = 159;
138   //  final static int TokenNameAT = 153; // @
139
140   public Parser() {
141   }
142
143   public void setFileToParse(IFile fileToParse) {
144     this.currentPHPString = 0;
145                 PHPParserSuperclass.fileToParse = fileToParse;
146     this.phpList = null;
147     this.str = "";
148     this.token = TokenNameEOF;
149     this.phpEnd = false;
150     this.initializeScanner();
151   }
152   /**
153    *  ClassDeclaration Constructor.
154    *
155    *@param  s
156    *@param  sess  Description of Parameter
157    *@see
158    */
159   public Parser(IFile fileToParse) {
160     //    if (keywordMap == null) {
161     //      keywordMap = new HashMap();
162     //      for (int i = 0; i < PHP_KEYWORS.length; i++) {
163     //        keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
164     //      }
165     //    }
166     this.currentPHPString = 0;
167                 PHPParserSuperclass.fileToParse = fileToParse;
168     this.phpList = null;
169     this.str = "";
170     this.token = TokenNameEOF;
171     //    this.chIndx = 0;
172     //    this.rowCount = 1;
173     //    this.columnCount = 0;
174     this.phpEnd = false;
175     //   getNextToken();
176
177     this.initializeScanner();
178   }
179
180   public void initializeScanner() {
181     this.scanner = new Scanner(false, false, false, false);
182   }
183   /**
184    * Create marker for the parse error
185    */
186   private void setMarker(String message, int charStart, int charEnd, int errorLevel) throws CoreException {
187     setMarker(fileToParse, message, charStart, charEnd, errorLevel);
188   }
189
190   /**
191    * This method will throw the SyntaxError.
192    * It will add the good lines and columns to the Error
193    * @param error the error message
194    * @throws SyntaxError the error raised
195    */
196   private void throwSyntaxError(String error) {
197
198     //    if (str.length() < chIndx) {
199     //      chIndx--;
200     //    }
201     //    // read until end-of-line
202     //    int eol = chIndx;
203     //    while (str.length() > eol) {
204     //      ch = str.charAt(eol++);
205     //      if (ch == '\n') {
206     //        eol--;
207     //        break;
208     //      }
209     //    }
210     //    throw new SyntaxError(
211     //      rowCount,
212     //      chIndx - columnCount + 1,
213     //      str.substring(columnCount, eol),
214     //      error);
215     throw new SyntaxError(1, 1, "", error);
216   }
217
218   /**
219    * This method will throw the SyntaxError.
220    * It will add the good lines and columns to the Error
221    * @param error the error message
222    * @throws SyntaxError the error raised
223    */
224   private void throwSyntaxError(String error, int startRow) {
225     throw new SyntaxError(startRow, 0, " ", error);
226   }
227
228   /**
229    *  Method Declaration.
230    *
231    *@see
232    */
233   //  private void getChar() {
234   //    if (str.length() > chIndx) {
235   //      ch = str.charAt(chIndx++);
236   //
237   //      return;
238   //    }
239   //
240   //    chIndx = str.length() + 1;
241   //    ch = ' ';
242   //    //  token = TokenNameEOF;
243   //    phpEnd = true;
244   //  }
245
246   /**
247    * gets the next token from input
248    */
249   private void getNextToken() throws CoreException {
250     try {
251       token = scanner.getNextToken();
252       if (Scanner.DEBUG) {
253         int currentEndPosition = scanner.getCurrentTokenEndPosition();
254         int currentStartPosition = scanner.getCurrentTokenStartPosition();
255
256         System.out.print(currentStartPosition + "," + currentEndPosition + ": ");
257         System.out.println(scanner.toStringAction(token));
258       }
259     } catch (InvalidInputException e) {
260       token = TokenNameERROR;
261     }
262     return;
263
264   }
265
266   /**
267    * Get a number.
268    * if it's a <code>double</code> the number will be stored in <code>doubleNumber</code> and the token will have the
269    * value {@link Parser#TokenNameDOUBLE_NUMBER}<br />
270    * if it's a <code>double</code> the number will be stored in <code>longNumber</code> and the token will have the
271    * value {@link Parser#TokenNameINT_NUMBER}
272    */
273   //  private void getNumber() {
274   //    StringBuffer inum = new StringBuffer();
275   //    char dFlag = ' ';
276   //    int numFormat = 10;
277   //
278   //    // save first digit
279   //    char firstCh = ch;
280   //    inum.append(ch);
281   //
282   //    getChar();
283   //    // determine number conversions:
284   //    if (firstCh == '0') {
285   //      switch (ch) {
286   //        case 'b' :
287   //          numFormat = 2;
288   //          getChar();
289   //          break;
290   //        case 'B' :
291   //          numFormat = 2;
292   //          getChar();
293   //          break;
294   //        case 'o' :
295   //          numFormat = 8;
296   //          getChar();
297   //          break;
298   //        case 'O' :
299   //          numFormat = 8;
300   //          getChar();
301   //          break;
302   //        case 'x' :
303   //          numFormat = 16;
304   //          getChar();
305   //          break;
306   //        case 'X' :
307   //          numFormat = 16;
308   //          getChar();
309   //          break;
310   //      }
311   //    }
312   //
313   //    if (numFormat == 16) {
314   //      while ((ch >= '0' && ch <= '9')
315   //        || (ch >= 'a' && ch <= 'f')
316   //        || (ch >= 'A' && ch <= 'F')) {
317   //        inum.append(ch);
318   //        getChar();
319   //      }
320   //    } else {
321   //      while ((ch >= '0' && ch <= '9')
322   //        || (ch == '.')
323   //        || (ch == 'E')
324   //        || (ch == 'e')) {
325   //        if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
326   //          if (ch == '.' && dFlag != ' ') {
327   //            break;
328   //          }
329   //          if ((dFlag == 'E') || (dFlag == 'e')) {
330   //            break;
331   //          }
332   //          dFlag = ch;
333   //          inum.append(ch);
334   //          getChar();
335   //          if ((ch == '-') || (ch == '+')) {
336   //            inum.append(ch);
337   //            getChar();
338   //          }
339   //        } else {
340   //          inum.append(ch);
341   //          getChar();
342   //        }
343   //      }
344   //    }
345   //    chIndx--;
346   //
347   //    try {
348   //      if (dFlag != ' ') {
349   //        doubleNumber = new Double(inum.toString());
350   //        token = TokenNameDoubleLiteral;
351   //        return;
352   //      } else {
353   //        longNumber = Long.valueOf(inum.toString(), numFormat);
354   //        token = TokenNameIntegerLiteral;
355   //        return;
356   //      }
357   //
358   //    } catch (Throwable e) {
359   //      throwSyntaxError("Number format error: " + inum.toString());
360   //    }
361   //  }
362   //
363   //  /**
364   //   * Get a String.
365   //   * @param openChar the opening char ('\'', '"', '`')
366   //   * @param typeString the type of string {@link #TokenNameSTRING_CONSTANT},{@link #TokenNameINTERPOLATED_STRING}
367   //   * @param errorMsg the error message in case of parse error in the string
368   //   */
369   //  private void getString(
370   //    final char openChar,
371   //    final int typeString,
372   //    final String errorMsg) {
373   //    StringBuffer sBuffer = new StringBuffer();
374   //    boolean openString = true;
375   //    int startRow = rowCount;
376   //    while (str.length() > chIndx) {
377   //      ch = str.charAt(chIndx++);
378   //      if (ch == '\\') {
379   //        sBuffer.append(ch);
380   //        if (str.length() > chIndx) {
381   //          ch = str.charAt(chIndx++);
382   //          sBuffer.append(ch);
383   //        }
384   //      } else if (ch == openChar) {
385   //        openString = false;
386   //        break;
387   //      } else if (ch == '\n') {
388   //        rowCount++;
389   //        columnCount = chIndx;
390   //      } else {
391   //        sBuffer.append(ch);
392   //      }
393   //    }
394   //    if (openString) {
395   //      if (typeString == TokenNameStringConstant) {
396   //        throwSyntaxError(errorMsg, startRow);
397   //      } else {
398   //        throwSyntaxError(errorMsg);
399   //      }
400   //    }
401   //    token = typeString;
402   //    stringValue = sBuffer.toString();
403   //  }
404
405   //    public void htmlParserTester(String input) {
406   //            int lineNumber = 1;
407   //            int startLineNumber = 1;
408   //            int startIndex = 0;
409   //            char ch;
410   //            char ch2;
411   //            boolean phpMode = false;
412   //            boolean phpFound = false;
413   //
414   //            phpList = new ArrayList();
415   //            currentPHPString = 0;
416   //
417   //            try {
418   //                    int i = 0;
419   //                    while (i < input.length()) {
420   //                            ch = input.charAt(i++);
421   //                            if (ch == '\n') {
422   //                                    lineNumber++;
423   //                            }
424   //                            if ((!phpMode) && ch == '<') {
425   //                                    ch2 = input.charAt(i++);
426   //                                    if (ch2 == '?') {
427   //                                            ch2 = input.charAt(i++);
428   //                                            if (Character.isWhitespace(ch2)) {
429   //                                                    // php start
430   //                                                    phpMode = true;
431   //                                                    phpFound = true;
432   //                                                    startIndex = i;
433   //                                                    startLineNumber = lineNumber;
434   //                                                    continue;
435   //                                            } else if (ch2 == 'p') {
436   //                                                    ch2 = input.charAt(i++);
437   //                                                    if (ch2 == 'h') {
438   //                                                            ch2 = input.charAt(i++);
439   //                                                            if (ch2 == 'p') {
440   //                                                                    phpMode = true;
441   //                                                                    phpFound = true;
442   //                                                                    startIndex = i;
443   //                                                                    startLineNumber = lineNumber;
444   //                                                                    continue;
445   //                                                            }
446   //                                                            i--;
447   //                                                    }
448   //                                                    i--;
449   //                                            } else if (ch2 == 'P') {
450   //                                                    ch2 = input.charAt(i++);
451   //                                                    if (ch2 == 'H') {
452   //                                                            ch2 = input.charAt(i++);
453   //                                                            if (ch2 == 'P') {
454   //                                                                    phpMode = true;
455   //                                                                    phpFound = true;
456   //                                                                    startIndex = i;
457   //                                                                    startLineNumber = lineNumber;
458   //                                                                    continue;
459   //                                                            }
460   //                                                            i--;
461   //                                                    }
462   //                                                    i--;
463   //                                            }
464   //                                            i--;
465   //                                    }
466   //                                    i--;
467   //                            }
468   //
469   //                            if (phpMode) {
470   //                                    if (ch == '/' && i < input.length()) {
471   //                                            ch2 = input.charAt(i++);
472   //                                            if (ch2 == '/') {
473   //                                                    while (i < input.length()) {
474   //                                                            ch = input.charAt(i++);
475   //                                                            if (ch == '?' && i < input.length()) {
476   //                                                                    ch2 = input.charAt(i++);
477   //                                                                    if (ch2 == '>') {
478   //                                                                            // php end
479   //                                                                            phpMode = false;
480   //                                                                            phpList.add(
481   //                                                                                    new PHPString(
482   //                                                                                            input.substring(
483   //                                                                                                    startIndex,
484   //                                                                                                    i - 2),
485   //                                                                                            startLineNumber));
486   //                                                                            continue;
487   //                                                                    }
488   //                                                                    i--;
489   //                                                            } else if (ch == '\n') {
490   //                                                                    lineNumber++;
491   //                                                                    break;
492   //                                                            }
493   //                                                    }
494   //                                                    continue;
495   //                                            } else if (ch2 == '*') {
496   //                                                    // multi-line comment
497   //                                                    while (i < input.length()) {
498   //                                                            ch = input.charAt(i++);
499   //                                                            if (ch == '\n') {
500   //                                                                    lineNumber++;
501   //                                                            } else if (ch == '*' && i < input.length()) {
502   //                                                                    ch2 = input.charAt(i++);
503   //                                                                    if (ch2 == '/') {
504   //                                                                            break;
505   //                                                                    }
506   //                                                                    i--;
507   //                                                            }
508   //                                                    }
509   //                                                    continue;
510   //                                            } else {
511   //                                                    i--;
512   //                                            }
513   //                                    } else if (ch == '#') {
514   //                                            while (i < input.length()) {
515   //                                                    ch = input.charAt(i++);
516   //                                                    if (ch == '?' && i < input.length()) {
517   //                                                            ch2 = input.charAt(i++);
518   //                                                            if (ch2 == '>') {
519   //                                                                    // php end
520   //                                                                    phpMode = false;
521   //                                                                    phpList.add(
522   //                                                                            new PHPString(
523   //                                                                                    input.substring(startIndex, i - 2),
524   //                                                                                    startLineNumber));
525   //                                                                    continue;
526   //                                                            }
527   //                                                            i--;
528   //                                                    } else if (ch == '\n') {
529   //                                                            lineNumber++;
530   //                                                            break;
531   //                                                    }
532   //                                            }
533   //                                            continue;
534   //                                    } else if (ch == '"') {
535   //                                            ch = ' ';
536   //                                            while (i < input.length()) {
537   //                                                    ch = input.charAt(i++);
538   //                                                    if (ch == '\n') {
539   //                                                            lineNumber++;
540   //                                                    } else if (
541   //                                                            ch == '\\' && i < input.length()) { // escape
542   //                                                            i++;
543   //                                                    } else if (ch == '"') {
544   //                                                            break;
545   //                                                    }
546   //                                            }
547   //                                            continue;
548   //                                    } else if (ch == '\'') {
549   //                                            ch = ' ';
550   //                                            while (i < input.length()) {
551   //                                                    ch = input.charAt(i++);
552   //                                                    if (ch == '\n') {
553   //                                                            lineNumber++;
554   //                                                    } else if (
555   //                                                            ch == '\\' && i < input.length()) { // escape
556   //                                                            i++;
557   //                                                    } else if (ch == '\'') {
558   //                                                            break;
559   //                                                    }
560   //                                            }
561   //                                            continue;
562   //                                    }
563   //
564   //                                    if (ch == '?' && i < input.length()) {
565   //                                            ch2 = input.charAt(i++);
566   //                                            if (ch2 == '>') {
567   //                                                    // php end
568   //                                                    phpMode = false;
569   //                                                    phpList.add(
570   //                                                            new PHPString(
571   //                                                                    input.substring(startIndex, i - 2),
572   //                                                                    startLineNumber));
573   //                                                    continue;
574   //                                            }
575   //                                            i--;
576   //                                    }
577   //                            }
578   //                    }
579   //
580   //                    if (!phpFound) {
581   //                            setMarker(
582   //                                    "No PHP source code found.",
583   //                                    lineNumber,
584   //                                    PHPParser.INFO);
585   //                    } else {
586   //                            if (phpMode) {
587   //                                    setMarker(
588   //                                            "Open PHP tag at end of file.",
589   //                                            lineNumber,
590   //                                            PHPParser.INFO);
591   //                                    phpList.add(
592   //                                            new PHPString(
593   //                                                    input.substring(startIndex, i - 2),
594   //                                                    startLineNumber));
595   //                            }
596   //                            //        for (int j=0;j<phpList.size();j++) {
597   //                            //          String temp = ((PHPString)phpList.get(j)).getPHPString();
598   //                            //          int startIndx = temp.length()-10;
599   //                            //          if (startIndx<0) {
600   //                            //            startIndx = 0;
601   //                            //          }
602   //                            //          System.out.println(temp.substring(startIndx)+"?>");
603   //                            //        }
604   //                            phpParserTester(null, 1);
605   //                            //        PHPString temp;
606   //                            //        for(int j=0;j<phpList.size();j++) {
607   //                            //          temp = (PHPString) phpList.get(j);
608   //                            //          parser.start(temp.getPHPString(), temp.getLineNumber());
609   //                            //        }
610   //                    }
611   //            } catch (CoreException e) {
612   //            }
613   //    }
614
615   public void phpParserTester(String s, int rowCount) throws CoreException {
616     this.str = s;
617     if (s == null) {
618       if (phpList.size() != 0) {
619         this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
620       }
621     }
622     this.token = TokenNameEOF;
623     //    this.chIndx = 0;
624     //    this.rowCount = rowCount;
625     //    this.columnCount = 0;
626     this.phpEnd = false;
627     this.phpMode = true;
628     scanner.setSource(s.toCharArray());
629     scanner.setPHPMode(true);
630     getNextToken();
631     do {
632       try {
633         if (token != TokenNameEOF && token != TokenNameERROR) {
634           statementList();
635         }
636         if (token != TokenNameEOF) {
637           if (token == TokenNameERROR) {
638             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
639           }
640           if (token == TokenNameRPAREN) {
641             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
642           }
643           if (token == TokenNameRBRACE) {
644             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
645           }
646           if (token == TokenNameRBRACKET) {
647             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
648           }
649
650           if (token == TokenNameLPAREN) {
651             throwSyntaxError("Read character '('; end-of-file not reached.");
652           }
653           if (token == TokenNameLBRACE) {
654             throwSyntaxError("Read character '{';  end-of-file not reached.");
655           }
656           if (token == TokenNameLBRACKET) {
657             throwSyntaxError("Read character '[';  end-of-file not reached.");
658           }
659
660           throwSyntaxError("End-of-file not reached.");
661         }
662         return;
663       } catch (SyntaxError err) {
664         if (s != null) {
665           throw err;
666         } else {
667           //   setMarker(err.getMessage(), err.getLine(), ERROR);
668           setMarker(err.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
669         }
670         // if an error occured,
671         // try to find keywords 'class' or 'function'
672         // to parse the rest of the string
673         while (token != TokenNameEOF && token != TokenNameERROR) {
674           if (token == TokenNameclass || token == TokenNamefunction) {
675             break;
676           }
677           getNextToken();
678         }
679         if (token == TokenNameEOF || token == TokenNameERROR) {
680           return;
681         }
682       }
683     }
684     while (true);
685   }
686
687   /**
688    * Parses a string with php tags
689    * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
690    */
691   public void parse(String s) throws CoreException {
692     this.str = s;
693     this.token = TokenNameEOF;
694     //    this.chIndx = 0;
695     //    this.rowCount = 1;
696     //    this.columnCount = 0;
697     this.phpEnd = false;
698     this.phpMode = false;
699     /* scanner initialization */
700     scanner.setSource(s.toCharArray());
701     scanner.setPHPMode(false);
702     getNextToken();
703     do {
704       try {
705         if (token != TokenNameEOF && token != TokenNameERROR) {
706           statementList();
707         }
708         if (token != TokenNameEOF) {
709           if (token == TokenNameERROR) {
710             throwSyntaxError("Scanner error (Found unknown token: " + scanner.toStringAction(token) + ")");
711           }
712           if (token == TokenNameRPAREN) {
713             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
714           }
715           if (token == TokenNameRBRACE) {
716             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
717           }
718           if (token == TokenNameRBRACKET) {
719             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
720           }
721
722           if (token == TokenNameLPAREN) {
723             throwSyntaxError("Read character '('; end-of-file not reached.");
724           }
725           if (token == TokenNameLBRACE) {
726             throwSyntaxError("Read character '{';  end-of-file not reached.");
727           }
728           if (token == TokenNameLBRACKET) {
729             throwSyntaxError("Read character '[';  end-of-file not reached.");
730           }
731
732           throwSyntaxError("End-of-file not reached.");
733         }
734         return;
735       } catch (SyntaxError sytaxErr1) {
736         // setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
737         setMarker(sytaxErr1.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
738         try {
739           // if an error occured,
740           // try to find keywords 'class' or 'function'
741           // to parse the rest of the string
742           while (token != TokenNameEOF && token != TokenNameERROR) {
743             if (token == TokenNameclass || token == TokenNamefunction) {
744               break;
745             }
746             getNextToken();
747           }
748           if (token == TokenNameEOF || token == TokenNameERROR) {
749             return;
750           }
751         } catch (SyntaxError sytaxErr2) {
752           //    setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
753           setMarker(sytaxErr2.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
754           return;
755         }
756       }
757     }
758     while (true);
759   }
760
761   public PHPOutlineInfo parseInfo(Object parent, String s) {
762     PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
763     //    Stack stack = new Stack();
764     //    stack.push(outlineInfo.getDeclarations());
765
766     this.str = s;
767     this.token = TokenNameEOF;
768     //    this.chIndx = 0;
769     //    this.rowCount = 1;
770     //    this.columnCount = 0;
771     this.phpEnd = false;
772     this.phpMode = false;
773     scanner.setSource(s.toCharArray());
774     scanner.setPHPMode(false);
775
776     try {
777       getNextToken();
778       parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
779     } catch (CoreException e) {
780     }
781     return outlineInfo;
782   }
783
784   private boolean isVariable() {
785     return token == TokenNameVariable || token == TokenNamethis;
786   }
787
788   private void parseDeclarations(PHPOutlineInfo outlineInfo, OutlineableWithChildren current, boolean goBack) {
789     char[] ident;
790     //   PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
791     PHPSegmentWithChildren temp;
792     int counter = 0;
793
794     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
795     try {
796       while (token != TokenNameEOF && token != TokenNameERROR) {
797         if (token == TokenNameVariable) {
798           ident = scanner.getCurrentIdentifierSource();
799           outlineInfo.addVariable(new String(ident));
800           getNextToken();
801         } else if (token == TokenNamevar) {
802           getNextToken();
803           if (token == TokenNameVariable && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
804             ident = scanner.getCurrentIdentifierSource();
805             //substring(1) added because PHPVarDeclaration doesn't need the $ anymore
806             String variableName = new String(ident).substring(1);
807             outlineInfo.addVariable(variableName);
808             getNextToken();
809             if (token != TokenNameSEMICOLON) {
810
811               getNextToken();
812               ident = scanner.getCurrentTokenSource();
813               if (token > TokenNameKEYWORD) {
814                 current.add(new PHPVarDeclaration(current, variableName,
815                 //                      chIndx - ident.length,
816                 scanner.getCurrentTokenStartPosition(), new String(ident)));
817               } else {
818                 switch (token) {
819                   case TokenNameVariable :
820                   case TokenNamethis :
821                     current.add(new PHPVarDeclaration(current, variableName,
822                     //                      chIndx - ident.length,
823                     scanner.getCurrentTokenStartPosition(), new String(ident)));
824                     break;
825                   case TokenNameIdentifier :
826                     current.add(new PHPVarDeclaration(current, variableName,
827                     //                    chIndx - ident.length,
828                     scanner.getCurrentTokenStartPosition(), new String(ident)));
829                     break;
830                   case TokenNameDoubleLiteral :
831                     current.add(new PHPVarDeclaration(current, variableName + doubleNumber,
832                     //   chIndx - ident.length,
833                     scanner.getCurrentTokenStartPosition(), new String(ident)));
834                     break;
835                   case TokenNameIntegerLiteral :
836                     current.add(new PHPVarDeclaration(current, variableName,
837                     //                 chIndx - ident.length,
838                     scanner.getCurrentTokenStartPosition(), new String(ident)));
839                     break;
840                   case TokenNameStringInterpolated :
841                   case TokenNameStringLiteral :
842                     current.add(new PHPVarDeclaration(current, variableName,
843                     //              chIndx - ident.length,
844                     scanner.getCurrentTokenStartPosition(), new String(ident)));
845                     break;
846                   case TokenNameStringConstant :
847                     current.add(new PHPVarDeclaration(current, variableName,
848                     //   chIndx - ident.length,
849                     scanner.getCurrentTokenStartPosition(), new String(ident)));
850                     break;
851                   default :
852                     current.add(new PHPVarDeclaration(current, variableName,
853                     //               chIndx - ident.length
854                     scanner.getCurrentTokenStartPosition()));
855                     break;
856                 }
857               }
858
859             } else {
860               ident = scanner.getCurrentIdentifierSource();
861
862               current.add(new PHPVarDeclaration(current, variableName,
863               //          chIndx - ident.length
864               scanner.getCurrentTokenStartPosition()));
865             }
866           }
867         } else if (token == TokenNamefunction) {
868           getNextToken();
869           if (token == TokenNameAND) {
870             getNextToken();
871           }
872           if (token == TokenNameIdentifier && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
873             ident = scanner.getCurrentIdentifierSource();
874             outlineInfo.addVariable(new String(ident));
875             temp = new PHPFunctionDeclaration(current, new String(ident),
876               // chIndx - ident.length
877   scanner.getCurrentTokenStartPosition());
878             current.add(temp);
879             getNextToken();
880             parseDeclarations(outlineInfo, temp, true);
881           }
882         } else if (token == TokenNameclass) {
883           getNextToken();
884           if (token == TokenNameIdentifier && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
885             ident = scanner.getCurrentIdentifierSource();
886             outlineInfo.addVariable(new String(ident));
887             temp = new PHPClassDeclaration(current, new String(ident),
888               //      chIndx - ident.len
889   scanner.getCurrentTokenStartPosition());
890             current.add(temp);
891             //        stack.push(temp);
892             getNextToken();
893
894             //skip tokens for classname, extends and others until we have the opening '{'
895             while (token != TokenNameLBRACE && token != TokenNameEOF && token != TokenNameERROR) {
896               getNextToken();
897             }
898             parseDeclarations(outlineInfo, temp, true);
899             //        stack.pop();
900           }
901         } else if ((token == TokenNameLBRACE) || (token == TokenNameDOLLAR_LBRACE)) {
902           getNextToken();
903           counter++;
904         } else if (token == TokenNameRBRACE) {
905           getNextToken();
906           --counter;
907           if (counter == 0 && goBack) {
908             return;
909           }
910         } else if (
911           token == TokenNamerequire
912             || token == TokenNamerequire_once
913             || token == TokenNameinclude
914             || token == TokenNameinclude_once) {
915           ident = scanner.getCurrentTokenSource();
916
917           getNextToken();
918           int startPosition = scanner.getCurrentTokenStartPosition();
919           expression();
920           char[] expr = scanner.getCurrentTokenSource(startPosition);
921           outlineInfo.addVariable(new String(ident));
922           current.add(new PHPReqIncDeclaration(current, new String(ident),
923           //    chIndx - ident.length,
924           startPosition, new String(expr)));
925           getNextToken();
926         } else {
927           getNextToken();
928         }
929       }
930     } catch (CoreException e) {
931     } catch (SyntaxError sytaxErr) {
932       try {
933         //  setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
934         setMarker(sytaxErr.getMessage(), scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), ERROR);
935       } catch (CoreException e) {
936       }
937     }
938   }
939
940   private void statementList() throws CoreException {
941     do {
942       statement(TokenNameEOF);
943       if ((token == TokenNameRBRACE)
944         || (token == TokenNamecase)
945         || (token == TokenNamedefault)
946         || (token == TokenNameelse)
947         || (token == TokenNameelseif)
948         || (token == TokenNameendif)
949         || (token == TokenNameendfor)
950         || (token == TokenNameendforeach)
951         || (token == TokenNameendwhile)
952         || (token == TokenNameendswitch)
953         || (token == TokenNameEOF)
954         || (token == TokenNameERROR)) {
955         return;
956       }
957     } while (true);
958   }
959
960   private void compoundStatement() throws CoreException {
961     // '{' [statement-list] '}'
962     if (token == TokenNameLBRACE) {
963       getNextToken();
964     } else {
965       throwSyntaxError("'{' expected in compound-statement.");
966     }
967     if (token != TokenNameRBRACE) {
968       statementList();
969     }
970     if (token == TokenNameRBRACE) {
971       getNextToken();
972     } else {
973       throwSyntaxError("'}' expected in compound-statement.");
974     }
975   }
976
977   private void statement(int previousToken) throws CoreException {
978     //   if (token > TokenNameKEYWORD && token != TokenNamelist && token != TokenNamenew) {
979     //  char[] ident = scanner.getCurrentIdentifierSource();
980     //  String keyword = new String(ident);
981     if (token == TokenNameinclude || token == TokenNameinclude_once) {
982       getNextToken();
983       if (token == TokenNameLPAREN) {
984         expression();
985         if (token == TokenNameSEMICOLON) {
986           getNextToken();
987         } else {
988           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
989             throwSyntaxError("';' expected after 'include' or 'include_once'.");
990           }
991           //        getNextToken();
992         }
993       } else {
994         concatenationExpression();
995       }
996
997       return;
998     } else if (token == TokenNamerequire || token == TokenNamerequire_once) {
999       getNextToken();
1000       //constant();
1001       if (token == TokenNameLPAREN) {
1002         expression();
1003         if (token == TokenNameSEMICOLON) {
1004           getNextToken();
1005         } else {
1006           if (previousToken != TokenNameAT && token != TokenNameStopPHP) {
1007             throwSyntaxError("';' expected after 'require' or 'require_once'.");
1008           }
1009           //        getNextToken();
1010         }
1011       } else {
1012         concatenationExpression();
1013       }
1014       return;
1015     } else if (token == TokenNameif) {
1016       getNextToken();
1017       if (token == TokenNameLPAREN) {
1018         getNextToken();
1019       } else {
1020         throwSyntaxError("'(' expected after 'if' keyword.");
1021       }
1022       expression();
1023       if (token == TokenNameRPAREN) {
1024         getNextToken();
1025       } else {
1026         throwSyntaxError("')' expected after 'if' condition.");
1027       }
1028       ifStatement();
1029       return;
1030
1031     } else if (token == TokenNameswitch) {
1032       getNextToken();
1033       if (token == TokenNameLPAREN) {
1034         getNextToken();
1035       } else {
1036         throwSyntaxError("'(' expected after 'switch' keyword.");
1037       }
1038       expression();
1039       if (token == TokenNameRPAREN) {
1040         getNextToken();
1041       } else {
1042         throwSyntaxError("')' expected after 'switch' condition.");
1043       }
1044       switchStatement();
1045       return;
1046     } else if (token == TokenNamefor) {
1047       getNextToken();
1048       if (token == TokenNameLPAREN) {
1049         getNextToken();
1050       } else {
1051         throwSyntaxError("'(' expected after 'for' keyword.");
1052       }
1053       if (token == TokenNameSEMICOLON) {
1054         getNextToken();
1055       } else {
1056         expressionList();
1057         if (token == TokenNameSEMICOLON) {
1058           getNextToken();
1059         } else {
1060           throwSyntaxError("';' expected after 'for'.");
1061         }
1062       }
1063       if (token == TokenNameSEMICOLON) {
1064         getNextToken();
1065       } else {
1066         expressionList();
1067         if (token == TokenNameSEMICOLON) {
1068           getNextToken();
1069         } else {
1070           throwSyntaxError("';' expected after 'for'.");
1071         }
1072       }
1073       if (token == TokenNameRPAREN) {
1074         getNextToken();
1075       } else {
1076         expressionList();
1077         if (token == TokenNameRPAREN) {
1078           getNextToken();
1079         } else {
1080           throwSyntaxError("')' expected after 'for'.");
1081         }
1082       }
1083       forStatement();
1084       return;
1085     } else if (token == TokenNamewhile) {
1086       getNextToken();
1087       if (token == TokenNameLPAREN) {
1088         getNextToken();
1089       } else {
1090         throwSyntaxError("'(' expected after 'while' keyword.");
1091       }
1092       expression();
1093       if (token == TokenNameRPAREN) {
1094         getNextToken();
1095       } else {
1096         throwSyntaxError("')' expected after 'while' condition.");
1097       }
1098       whileStatement();
1099       return;
1100     } else if (token == TokenNamedo) {
1101       getNextToken();
1102       if (token == TokenNameLBRACE) {
1103         getNextToken();
1104       } else {
1105         throwSyntaxError("'{' expected after 'do' keyword.");
1106       }
1107       if (token != TokenNameRBRACE) {
1108         statementList();
1109       }
1110       if (token == TokenNameRBRACE) {
1111         getNextToken();
1112       } else {
1113         throwSyntaxError("'}' expected after 'do' keyword.");
1114       }
1115       if (token == TokenNamewhile) {
1116         getNextToken();
1117         if (token == TokenNameLPAREN) {
1118           getNextToken();
1119         } else {
1120           throwSyntaxError("'(' expected after 'while' keyword.");
1121         }
1122         expression();
1123         if (token == TokenNameRPAREN) {
1124           getNextToken();
1125         } else {
1126           throwSyntaxError("')' expected after 'while' condition.");
1127         }
1128       } else {
1129         throwSyntaxError("'while' expected after 'do' keyword.");
1130       }
1131       if (token == TokenNameSEMICOLON) {
1132         getNextToken();
1133       } else {
1134         if (token != TokenNameStopPHP) {
1135           throwSyntaxError("';' expected after do-while statement.");
1136         }
1137         getNextToken();
1138       }
1139       return;
1140     } else if (token == TokenNameforeach) {
1141       getNextToken();
1142       if (token == TokenNameLPAREN) {
1143         getNextToken();
1144       } else {
1145         throwSyntaxError("'(' expected after 'foreach' keyword.");
1146       }
1147       expression();
1148       if (token == TokenNameas) {
1149         getNextToken();
1150       } else {
1151         throwSyntaxError("'as' expected after 'foreach' exxpression.");
1152       }
1153       variable();
1154       if (token == TokenNameEQUAL_GREATER) {
1155         getNextToken();
1156         variable();
1157       }
1158       if (token == TokenNameRPAREN) {
1159         getNextToken();
1160       } else {
1161         throwSyntaxError("')' expected after 'foreach' expression.");
1162       }
1163       foreachStatement();
1164       return;
1165
1166     } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) {
1167       getNextToken();
1168       if (token != TokenNameSEMICOLON) {
1169         expression();
1170       }
1171       if (token == TokenNameSEMICOLON) {
1172         getNextToken();
1173       } else {
1174         if (token != TokenNameStopPHP) {
1175           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
1176         }
1177         getNextToken();
1178       }
1179       return;
1180
1181     } else if (token == TokenNameecho) {
1182       getNextToken();
1183       expressionList();
1184       if (token == TokenNameSEMICOLON) {
1185         getNextToken();
1186       } else {
1187         if (token != TokenNameStopPHP) {
1188           throwSyntaxError("';' expected after 'echo' statement.");
1189         }
1190         getNextToken();
1191       }
1192       return;
1193       //    } else if (token == TokenNameprint) {
1194       //      getNextToken();
1195       //      expression();
1196       //      if (token == TokenNameSEMICOLON) {
1197       //        getNextToken();
1198       //      } else {
1199       //        if (token != TokenNameStopPHP) {
1200       //          throwSyntaxError("';' expected after 'print' statement.");
1201       //        }
1202       //        getNextToken();
1203       //      }
1204       //      return;
1205
1206     } else if (token == TokenNameglobal || token == TokenNamestatic) {
1207       getNextToken();
1208       variableList();
1209       if (token == TokenNameSEMICOLON) {
1210         getNextToken();
1211       } else {
1212         if (token != TokenNameStopPHP) {
1213           throwSyntaxError("';' expected after 'global' or 'static' statement.");
1214         }
1215         getNextToken();
1216       }
1217       return;
1218
1219       //      } else if (token == TokenNameunset) {
1220       //        getNextToken();
1221       //        if (token == TokenNameARGOPEN) {
1222       //          getNextToken();
1223       //        } else {
1224       //          throwSyntaxError("'(' expected after 'unset' keyword.");
1225       //        }
1226       //        variableList();
1227       //        if (token == TokenNameARGCLOSE) {
1228       //          getNextToken();
1229       //        } else {
1230       //          throwSyntaxError("')' expected after 'unset' statement.");
1231       //        }
1232       //        if (token == TokenNameSEMICOLON) {
1233       //          getNextToken();
1234       //        } else {
1235       //          if (token != TokenNameStopPHP) {
1236       //            throwSyntaxError("';' expected after 'unset' statement.");
1237       //          }
1238       //          getNextToken();
1239       //        }
1240       //        return;
1241
1242       //      } else if (token == TokenNameexit || token == TokenNamedie) {
1243       //        getNextToken();
1244       //        if (token != TokenNameSEMICOLON) {
1245       //          exitStatus();
1246       //        }
1247       //        if (token == TokenNameSEMICOLON) {
1248       //          getNextToken();
1249       //        } else {
1250       //          if (token != TokenNameStopPHP) {
1251       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
1252       //          }
1253       //          getNextToken();
1254       //        }
1255       //        return;
1256
1257     } else if (token == TokenNamedefine) {
1258       getNextToken();
1259       if (token == TokenNameLPAREN) {
1260         getNextToken();
1261       } else {
1262         throwSyntaxError("'(' expected after 'define' keyword.");
1263       }
1264       expression();
1265       if (token == TokenNameCOMMA) {
1266         getNextToken();
1267       } else {
1268         throwSyntaxError("',' expected after first 'define' constant.");
1269       }
1270       expression();
1271       if (token == TokenNameCOMMA) {
1272         getNextToken();
1273         expression();
1274       }
1275       if (token == TokenNameRPAREN) {
1276         getNextToken();
1277       } else {
1278         throwSyntaxError("')' expected after 'define' statement.");
1279       }
1280       if (token == TokenNameSEMICOLON) {
1281         getNextToken();
1282       } else {
1283         if (token != TokenNameStopPHP) {
1284           throwSyntaxError("';' expected after 'define' statement.");
1285         }
1286         getNextToken();
1287       }
1288       return;
1289     } else if (token == TokenNamefunction) {
1290       getNextToken();
1291       functionDefinition();
1292       return;
1293     } else if (token == TokenNameclass) {
1294       getNextToken();
1295       classDeclarator();
1296       classBody();
1297       return;
1298       //      } else {
1299       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
1300     } else if (token == TokenNameLBRACE) {
1301       // compoundStatement
1302       getNextToken();
1303       if (token != TokenNameRBRACE) {
1304         statementList();
1305       }
1306       if (token == TokenNameRBRACE) {
1307         getNextToken();
1308         return;
1309       } else {
1310         throwSyntaxError("'}' expected.");
1311       }
1312     } else {
1313       if (token != TokenNameSEMICOLON) {
1314         expression();
1315       }
1316       if (token == TokenNameSEMICOLON) {
1317         getNextToken();
1318         return;
1319       } else {
1320         if (token != TokenNameStopPHP && token != TokenNameEOF) {
1321           throwSyntaxError("';' expected after expression (Found token: " + scanner.toStringAction(token) + ")");
1322         }
1323         getNextToken();
1324       }
1325     }
1326   }
1327
1328   private void classDeclarator() throws CoreException {
1329     //identifier
1330     //identifier 'extends' identifier
1331     if (token == TokenNameIdentifier) {
1332       getNextToken();
1333       if (token == TokenNameextends) {
1334         do {
1335           getNextToken();
1336           if (token == TokenNameIdentifier) {
1337             getNextToken();
1338           } else {
1339             throwSyntaxError("ClassDeclaration name expected after keyword 'extends'.");
1340           }
1341         } while (token == TokenNameCOMMA);
1342       }
1343     } else {
1344       if (token > TokenNameKEYWORD) {
1345         throwSyntaxError("Don't use keyword for class declaration [" + token + "].");
1346       }
1347       throwSyntaxError("ClassDeclaration name expected after keyword 'class'.");
1348     }
1349   }
1350
1351   private void classBody() throws CoreException {
1352     //'{' [class-element-list] '}'
1353     if (token == TokenNameLBRACE) {
1354       getNextToken();
1355       if (token != TokenNameRBRACE) {
1356         classElementList();
1357       }
1358       if (token == TokenNameRBRACE) {
1359         getNextToken();
1360       } else {
1361         throwSyntaxError("'}' expected at end of class body.");
1362       }
1363     } else {
1364       throwSyntaxError("'{' expected at start of class body.");
1365     }
1366   }
1367
1368   private void classElementList() throws CoreException {
1369     do {
1370       classElement();
1371     } while (token == TokenNamefunction || token == TokenNamevar);
1372   }
1373
1374   private void classElement() throws CoreException {
1375     //class-property
1376     //function-definition
1377     if (token == TokenNamefunction) {
1378       getNextToken();
1379       functionDefinition();
1380     } else if (token == TokenNamevar) {
1381       getNextToken();
1382       classProperty();
1383     } else {
1384       throwSyntaxError("'function' or 'var' expected.");
1385     }
1386   }
1387
1388   private void classProperty() throws CoreException {
1389     //'var' variable ';'
1390     //'var' variable '=' constant ';'
1391     do {
1392       if (token == TokenNameVariable) {
1393         getNextToken();
1394         if (token == TokenNameEQUAL) {
1395           getNextToken();
1396           constant();
1397         }
1398       } else {
1399         if (token == TokenNamethis) {
1400           throwSyntaxError("Reserved word '$this' not allowed after keyword 'var'.");
1401         }
1402         throwSyntaxError("Variable expected after keyword 'var'.");
1403       }
1404       if (token != TokenNameCOMMA) {
1405         break;
1406       }
1407       getNextToken();
1408     } while (true);
1409     if (token == TokenNameSEMICOLON) {
1410       getNextToken();
1411     } else {
1412       throwSyntaxError("';' expected after variable declaration.");
1413     }
1414   }
1415
1416   private void functionDefinition() throws CoreException {
1417     functionDeclarator();
1418     compoundStatement();
1419   }
1420
1421   private void functionDeclarator() throws CoreException {
1422     //identifier '(' [parameter-list] ')'
1423     if (token == TokenNameAND) {
1424       getNextToken();
1425     }
1426     if (token == TokenNameIdentifier) {
1427       getNextToken();
1428       if (token == TokenNameLPAREN) {
1429         getNextToken();
1430       } else {
1431         throwSyntaxError("'(' expected in function declaration.");
1432       }
1433       if (token != TokenNameRPAREN) {
1434         parameterList();
1435       }
1436       if (token != TokenNameRPAREN) {
1437         throwSyntaxError("')' expected in function declaration.");
1438       } else {
1439         getNextToken();
1440       }
1441     } else {
1442       if (token > TokenNameKEYWORD) {
1443         throwSyntaxError("Don't use keyword for function declaration [" + token + "].");
1444       }
1445       throwSyntaxError("Function name expected after keyword 'function'.");
1446     }
1447   }
1448   //
1449   private void parameterList() throws CoreException {
1450     //parameter-declaration
1451     //parameter-list ',' parameter-declaration
1452     do {
1453       parameterDeclaration();
1454       if (token != TokenNameCOMMA) {
1455         break;
1456       }
1457       getNextToken();
1458     } while (true);
1459   }
1460
1461   private void parameterDeclaration() throws CoreException {
1462     //variable
1463     //variable-reference
1464     if (token == TokenNameAND) {
1465       getNextToken();
1466       if (isVariable()) {
1467         getNextToken();
1468       } else {
1469         throwSyntaxError("Variable expected after reference operator '&'.");
1470       }
1471     }
1472     //variable '=' constant
1473     if (token == TokenNameVariable) {
1474       getNextToken();
1475       if (token == TokenNameEQUAL) {
1476         getNextToken();
1477         constant();
1478       }
1479       return;
1480     }
1481     if (token == TokenNamethis) {
1482       throwSyntaxError("Reserved word '$this' not allowed in parameter declaration.");
1483     }
1484   }
1485
1486   private void labeledStatementList() throws CoreException {
1487     if (token != TokenNamecase && token != TokenNamedefault) {
1488       throwSyntaxError("'case' or 'default' expected.");
1489     }
1490     do {
1491       if (token == TokenNamecase) {
1492         getNextToken();
1493         expression(); //constant();
1494         if (token == TokenNameCOLON) {
1495           getNextToken();
1496           if (token == TokenNamecase || token == TokenNamedefault) { // empty case statement ?
1497             continue;
1498           }
1499           statementList();
1500         } else if (token == TokenNameSEMICOLON) {
1501           //          setMarker(
1502           //            "':' expected after 'case' keyword (Found token: "
1503           //              + scanner.toStringAction(token)
1504           //              + ")",
1505           //            rowCount,
1506           //            PHPParser.INFO);
1507           setMarker(
1508             "':' expected after 'case' keyword (Found token: " + scanner.toStringAction(token) + ")",
1509             scanner.getCurrentTokenStartPosition(),
1510             scanner.getCurrentTokenEndPosition(),
1511             INFO);
1512           getNextToken();
1513           if (token == TokenNamecase) { // empty case statement ?
1514             continue;
1515           }
1516           statementList();
1517         } else {
1518           throwSyntaxError("':' character after 'case' constant expected (Found token: " + scanner.toStringAction(token) + ")");
1519         }
1520       } else { // TokenNamedefault
1521         getNextToken();
1522         if (token == TokenNameCOLON) {
1523           getNextToken();
1524           statementList();
1525         } else {
1526           throwSyntaxError("':' character after 'default' expected.");
1527         }
1528       }
1529     } while (token == TokenNamecase || token == TokenNamedefault);
1530   }
1531
1532   //  public void labeledStatement() {
1533   //    if (token == TokenNamecase) {
1534   //      getNextToken();
1535   //      constant();
1536   //      if (token == TokenNameDDOT) {
1537   //        getNextToken();
1538   //        statement();
1539   //      } else {
1540   //        throwSyntaxError("':' character after 'case' constant expected.");
1541   //      }
1542   //      return;
1543   //    } else if (token == TokenNamedefault) {
1544   //      getNextToken();
1545   //      if (token == TokenNameDDOT) {
1546   //        getNextToken();
1547   //        statement();
1548   //      } else {
1549   //        throwSyntaxError("':' character after 'default' expected.");
1550   //      }
1551   //      return;
1552   //    }
1553   //  }
1554
1555   //  public void expressionStatement() {
1556   //  }
1557
1558   //  private void inclusionStatement() {
1559   //  }
1560
1561   //  public void compoundStatement() {
1562   //  }
1563
1564   //  public void selectionStatement() {
1565   //  }
1566   //
1567   //  public void iterationStatement() {
1568   //  }
1569   //
1570   //  public void jumpStatement() {
1571   //  }
1572   //
1573   //  public void outputStatement() {
1574   //  }
1575   //
1576   //  public void scopeStatement() {
1577   //  }
1578   //
1579   //  public void flowStatement() {
1580   //  }
1581   //
1582   //  public void definitionStatement() {
1583   //  }
1584
1585   private void ifStatement() throws CoreException {
1586     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1587     if (token == TokenNameCOLON) {
1588       getNextToken();
1589       if (token != TokenNameendif) {
1590         statementList();
1591         switch (token) {
1592           case TokenNameelse :
1593             getNextToken();
1594             if (token == TokenNameCOLON) {
1595               getNextToken();
1596               if (token != TokenNameendif) {
1597                 statementList();
1598               }
1599             } else {
1600               if (token == TokenNameif) { //'else if'
1601                 getNextToken();
1602                 elseifStatementList();
1603               } else {
1604                 throwSyntaxError("':' expected after 'else'.");
1605               }
1606             }
1607             break;
1608           case TokenNameelseif :
1609             getNextToken();
1610             elseifStatementList();
1611             break;
1612         }
1613       }
1614
1615       if (token != TokenNameendif) {
1616         throwSyntaxError("'endif' expected.");
1617       }
1618       getNextToken();
1619       if (token != TokenNameSEMICOLON) {
1620         throwSyntaxError("';' expected after if-statement.");
1621       }
1622       getNextToken();
1623     } else {
1624       // statement [else-statement]
1625       statement(TokenNameEOF);
1626       if (token == TokenNameelseif) {
1627         getNextToken();
1628         if (token == TokenNameLPAREN) {
1629           getNextToken();
1630         } else {
1631           throwSyntaxError("'(' expected after 'elseif' keyword.");
1632         }
1633         expression();
1634         if (token == TokenNameRPAREN) {
1635           getNextToken();
1636         } else {
1637           throwSyntaxError("')' expected after 'elseif' condition.");
1638         }
1639         ifStatement();
1640       } else if (token == TokenNameelse) {
1641         getNextToken();
1642         statement(TokenNameEOF);
1643       }
1644     }
1645   }
1646
1647   private void elseifStatementList() throws CoreException {
1648     do {
1649       elseifStatement();
1650       switch (token) {
1651         case TokenNameelse :
1652           getNextToken();
1653           if (token == TokenNameCOLON) {
1654             getNextToken();
1655             if (token != TokenNameendif) {
1656               statementList();
1657             }
1658             return;
1659           } else {
1660             if (token == TokenNameif) { //'else if'
1661               getNextToken();
1662             } else {
1663               throwSyntaxError("':' expected after 'else'.");
1664             }
1665           }
1666           break;
1667         case TokenNameelseif :
1668           getNextToken();
1669           break;
1670         default :
1671           return;
1672       }
1673     } while (true);
1674   }
1675
1676   private void elseifStatement() throws CoreException {
1677     if (token == TokenNameLPAREN) {
1678       getNextToken();
1679       expression();
1680       if (token != TokenNameRPAREN) {
1681         throwSyntaxError("')' expected in else-if-statement.");
1682       }
1683       getNextToken();
1684       if (token != TokenNameCOLON) {
1685         throwSyntaxError("':' expected in else-if-statement.");
1686       }
1687       getNextToken();
1688       if (token != TokenNameendif) {
1689         statementList();
1690       }
1691     }
1692   }
1693
1694   private void switchStatement() throws CoreException {
1695     if (token == TokenNameCOLON) {
1696       // ':' [labeled-statement-list] 'endswitch' ';'
1697       getNextToken();
1698       labeledStatementList();
1699       if (token != TokenNameendswitch) {
1700         throwSyntaxError("'endswitch' expected.");
1701       }
1702       getNextToken();
1703       if (token != TokenNameSEMICOLON) {
1704         throwSyntaxError("';' expected after switch-statement.");
1705       }
1706       getNextToken();
1707     } else {
1708       // '{' [labeled-statement-list] '}'
1709       if (token != TokenNameLBRACE) {
1710         throwSyntaxError("'{' expected in switch statement.");
1711       }
1712       getNextToken();
1713       if (token != TokenNameRBRACE) {
1714         labeledStatementList();
1715       }
1716       if (token != TokenNameRBRACE) {
1717         throwSyntaxError("'}' expected in switch statement.");
1718       }
1719       getNextToken();
1720
1721     }
1722   }
1723
1724   private void forStatement() throws CoreException {
1725     if (token == TokenNameCOLON) {
1726       getNextToken();
1727       statementList();
1728       if (token != TokenNameendfor) {
1729         throwSyntaxError("'endfor' expected.");
1730       }
1731       getNextToken();
1732       if (token != TokenNameSEMICOLON) {
1733         throwSyntaxError("';' expected after for-statement.");
1734       }
1735       getNextToken();
1736     } else {
1737       statement(TokenNameEOF);
1738     }
1739   }
1740
1741   private void whileStatement() throws CoreException {
1742     // ':' statement-list 'endwhile' ';'
1743     if (token == TokenNameCOLON) {
1744       getNextToken();
1745       statementList();
1746       if (token != TokenNameendwhile) {
1747         throwSyntaxError("'endwhile' expected.");
1748       }
1749       getNextToken();
1750       if (token != TokenNameSEMICOLON) {
1751         throwSyntaxError("';' expected after while-statement.");
1752       }
1753       getNextToken();
1754     } else {
1755       statement(TokenNameEOF);
1756     }
1757   }
1758
1759   private void foreachStatement() throws CoreException {
1760     if (token == TokenNameCOLON) {
1761       getNextToken();
1762       statementList();
1763       if (token != TokenNameendforeach) {
1764         throwSyntaxError("'endforeach' expected.");
1765       }
1766       getNextToken();
1767       if (token != TokenNameSEMICOLON) {
1768         throwSyntaxError("';' expected after foreach-statement.");
1769       }
1770       getNextToken();
1771     } else {
1772       statement(TokenNameEOF);
1773     }
1774   }
1775
1776   private void exitStatus() throws CoreException {
1777     if (token == TokenNameLPAREN) {
1778       getNextToken();
1779     } else {
1780       throwSyntaxError("'(' expected in 'exit-status'.");
1781     }
1782     if (token != TokenNameRPAREN) {
1783       expression();
1784     }
1785     if (token == TokenNameRPAREN) {
1786       getNextToken();
1787     } else {
1788       throwSyntaxError("')' expected after 'exit-status'.");
1789     }
1790   }
1791
1792   private void expressionList() throws CoreException {
1793     do {
1794       expression();
1795       if (token == TokenNameCOMMA) {
1796         getNextToken();
1797       } else {
1798         break;
1799       }
1800     } while (true);
1801   }
1802
1803   private void expression() throws CoreException {
1804     //todo: find a better way to get the expression
1805     //    expression = new StringBuffer();
1806     //    for (int i = chIndx; i < str.length(); i++) {
1807     //      if (str.charAt(i) == ';') {
1808     //        break;
1809     //      }
1810     //      expression.append(str.charAt(i));
1811     //    }
1812
1813     //    if (token == TokenNameSTRING_CONSTANT || token == TokenNameINTERPOLATED_STRING) {
1814     //      getNextToken();
1815     //    } else {
1816     logicalinclusiveorExpression();
1817     //      while (token != TokenNameSEMICOLON) {
1818     //        getNextToken();
1819     //      //      }
1820     //    }
1821   }
1822
1823   private void postfixExpression() throws CoreException {
1824     //  String ident;
1825     char[] ident;
1826     boolean castFlag = false;
1827     boolean arrayFlag = false;
1828     switch (token) {
1829       case TokenNamenew :
1830         getNextToken();
1831         expression();
1832         break;
1833       case TokenNamenull :
1834         getNextToken();
1835         break;
1836       case TokenNamefalse :
1837         getNextToken();
1838         break;
1839       case TokenNametrue :
1840         getNextToken();
1841         break;
1842       case TokenNameStringConstant :
1843         getNextToken();
1844         break;
1845       case TokenNameHEREDOC :
1846       case TokenNameStringInterpolated :
1847       case TokenNameStringLiteral :
1848         getNextToken();
1849         break;
1850       case TokenNameLPAREN :
1851         getNextToken();
1852
1853         if (token == TokenNameIdentifier) {
1854           // check if identifier is a type:
1855           //    ident = identifier;
1856           ident = scanner.getCurrentIdentifierSource();
1857           String str = new String(ident).toLowerCase();
1858           for (int i = 0; i < PHP_TYPES.length; i++) {
1859             if (PHP_TYPES[i].equals(str)) {
1860               castFlag = true;
1861               if (PHP_TYPES[i].equals("array")) {
1862                 arrayFlag = true;
1863               }
1864               break;
1865             }
1866           }
1867         }
1868
1869         if (castFlag) {
1870           getNextToken();
1871           if (arrayFlag && token == TokenNameLPAREN) {
1872             getNextToken();
1873             if (token == TokenNameRPAREN) {
1874               getNextToken();
1875             } else {
1876               expression();
1877               if (token != TokenNameRPAREN) {
1878                 throwSyntaxError(") expected after 'array('.");
1879               }
1880             }
1881           }
1882           if (token != TokenNameRPAREN) {
1883             throwSyntaxError(") expected after cast-type '" + str + "'.");
1884           }
1885           getNextToken();
1886           expression();
1887           break;
1888         } else {
1889           expression();
1890         }
1891         if (token != TokenNameRPAREN) {
1892           throwSyntaxError(") expected in postfix-expression.");
1893         }
1894         getNextToken();
1895         break;
1896       case TokenNameDoubleLiteral :
1897         getNextToken();
1898         break;
1899       case TokenNameIntegerLiteral :
1900         getNextToken();
1901         break;
1902       case TokenNameDOLLAR_LBRACE :
1903         getNextToken();
1904         expression();
1905         if (token != TokenNameRBRACE) {
1906           throwSyntaxError("'}' expected after indirect variable token '${'.");
1907         }
1908         getNextToken();
1909         break;
1910       case TokenNameVariable :
1911       case TokenNamethis :
1912         ident = scanner.getCurrentIdentifierSource();
1913         getNextToken();
1914         if (token == TokenNameLBRACE) {
1915           getNextToken();
1916           expression();
1917           if (token != TokenNameRBRACE) {
1918             throwSyntaxError("'}' expected after variable '" + new String(ident) + "' in variable-expression.");
1919           }
1920           getNextToken();
1921         } else if (token == TokenNameLPAREN) {
1922           getNextToken();
1923           if (token != TokenNameRPAREN) {
1924             expressionList();
1925             if (token != TokenNameRPAREN) {
1926               throwSyntaxError("')' expected after variable '" + new String(ident) + "' in postfix-expression.");
1927             }
1928           }
1929           getNextToken();
1930         }
1931         break;
1932       case TokenNameIdentifier :
1933         ident = scanner.getCurrentIdentifierSource();
1934         getNextToken();
1935         if (token == TokenNameLPAREN) {
1936           getNextToken();
1937           if (token != TokenNameRPAREN) {
1938             expressionList();
1939             if (token != TokenNameRPAREN) {
1940               throwSyntaxError(
1941                 "')' expected after identifier '"
1942                   + new String(ident)
1943                   + "' in postfix-expression."
1944                   + "(Found token: "
1945                   + scanner.toStringAction(token)
1946                   + ")");
1947             }
1948           }
1949           getNextToken();
1950         }
1951         break;
1952       case TokenNameprint :
1953         getNextToken();
1954         expression();
1955         //        if (token == TokenNameSEMICOLON) {
1956         //          getNextToken();
1957         //        } else {
1958         //          if (token != TokenNameStopPHP) {
1959         //            throwSyntaxError("';' expected after 'print' statement.");
1960         //          }
1961         //          getNextToken();
1962         //        }
1963         break;
1964       case TokenNamelist :
1965         getNextToken();
1966         if (token == TokenNameLPAREN) {
1967           getNextToken();
1968           if (token == TokenNameCOMMA) {
1969             getNextToken();
1970           }
1971           expressionList();
1972           if (token != TokenNameRPAREN) {
1973             throwSyntaxError("')' expected after 'list' keyword.");
1974           }
1975           getNextToken();
1976           //          if (token == TokenNameSET) {
1977           //            getNextToken();
1978           //            logicalinclusiveorExpression();
1979           //          }
1980         } else {
1981           throwSyntaxError("'(' expected after 'list' keyword.");
1982         }
1983         break;
1984         //      case TokenNameexit :
1985         //        getNextToken();
1986         //        if (token != TokenNameSEMICOLON) {
1987         //          exitStatus();
1988         //        }
1989         //        if (token == TokenNameSEMICOLON) {
1990         //          getNextToken();
1991         //        } else {
1992         //          if (token != TokenNameStopPHP) {
1993         //            throwSyntaxError("';' expected after 'exit' expression.");
1994         //          }
1995         //          getNextToken();
1996         //        }
1997         //        break;
1998         //      case TokenNamedie :
1999         //        getNextToken();
2000         //        if (token != TokenNameSEMICOLON) {
2001         //          exitStatus();
2002         //        }
2003         //        if (token == TokenNameSEMICOLON) {
2004         //          getNextToken();
2005         //        } else {
2006         //          if (token != TokenNameStopPHP) {
2007         //            throwSyntaxError("';' expected after 'die' expression.");
2008         //          }
2009         //        }
2010         //        break;
2011
2012         //      case TokenNamearray :
2013         //        getNextToken();
2014         //        if (token == TokenNameARGOPEN) {
2015         //          getNextToken();
2016         //          if (token == TokenNameCOMMA) {
2017         //            getNextToken();
2018         //          }
2019         //          expressionList();
2020         //          if (token != TokenNameARGCLOSE) {
2021         //            throwSyntaxError("')' expected after 'list' keyword.");
2022         //          }
2023         //          getNextToken();
2024         //          if (token == TokenNameSET) {
2025         //            getNextToken();
2026         //            logicalinclusiveorExpression();
2027         //          }
2028         //        } else {
2029         //          throwSyntaxError("'(' expected after 'list' keyword.");
2030         //        }
2031         //        break;
2032     }
2033     boolean while_flag = true;
2034     do {
2035       switch (token) {
2036         case TokenNameLBRACKET :
2037           getNextToken();
2038           expression();
2039           if (token != TokenNameRBRACKET) {
2040             throwSyntaxError("] expected in postfix-expression.");
2041           }
2042           getNextToken();
2043           break;
2044         case TokenNameCOLON_COLON : // ::
2045         case TokenNameMINUS_GREATER : // ->
2046           getNextToken();
2047           if (token > TokenNameKEYWORD) {
2048             ident = scanner.getCurrentIdentifierSource();
2049             //            setMarker(
2050             //              "Avoid using keyword '"
2051             //                + new String(ident)
2052             //                + "' as variable name.",
2053             //              rowCount,
2054             //              PHPParser.INFO);
2055             setMarker(
2056               "Avoid using keyword '" + new String(ident) + "' as variable name.",
2057               scanner.getCurrentTokenStartPosition(),
2058               scanner.getCurrentTokenEndPosition(),
2059               INFO);
2060           }
2061           switch (token) {
2062             case TokenNameVariable :
2063               ident = scanner.getCurrentIdentifierSource();
2064               getNextToken();
2065               //              if (token == TokenNameARGOPEN) {
2066               //                getNextToken();
2067               //                expressionList();
2068               //                if (token != TokenNameARGCLOSE) {
2069               //                  throwSyntaxError(") expected after variable '" + ident + "'.");
2070               //                }
2071               //                getNextToken();
2072               //              }
2073               break;
2074             case TokenNameIdentifier :
2075               //ident = scanner.getCurrentIdentifierSource();
2076               getNextToken();
2077               break;
2078             case TokenNameLBRACE :
2079               getNextToken();
2080               expression();
2081               if (token != TokenNameRBRACE) {
2082                 throwSyntaxError("} expected in postfix-expression.");
2083               }
2084               getNextToken();
2085               break;
2086             default :
2087               throwSyntaxError("Syntax error after '->' token.");
2088           } while (token == TokenNameLBRACKET || token == TokenNameLPAREN || token == TokenNameLBRACE) {
2089               if (token == TokenNameLBRACKET) {
2090                 getNextToken();
2091                 expressionList();
2092                 if (token != TokenNameRBRACKET) {
2093                   throwSyntaxError("] expected after '->'.");
2094                 }
2095                 getNextToken();
2096               } else if (token == TokenNameLPAREN) {
2097                 getNextToken();
2098                 expressionList();
2099                 if (token != TokenNameRPAREN) {
2100                   throwSyntaxError(") expected after '->'.");
2101                 }
2102                 getNextToken();
2103               } else if (token == TokenNameLBRACE) {
2104                 getNextToken();
2105                 expression();
2106                 if (token != TokenNameRBRACE) {
2107                   throwSyntaxError("} expected after '->'.");
2108                 }
2109                 getNextToken();
2110               }
2111             }
2112           break;
2113         case TokenNamePLUS_PLUS :
2114           getNextToken();
2115           break;
2116         case TokenNameMINUS_MINUS :
2117           getNextToken();
2118           break;
2119         default :
2120           while_flag = false;
2121       }
2122
2123     }
2124     while (while_flag);
2125   }
2126
2127   private void unaryExpression() throws CoreException {
2128     switch (token) {
2129       case TokenNamePLUS_PLUS :
2130         getNextToken();
2131         unaryExpression();
2132         break;
2133       case TokenNameMINUS_MINUS :
2134         getNextToken();
2135         unaryExpression();
2136         break;
2137         // '@' '&' '*' '+' '-' '~' '!'
2138       case TokenNameAT :
2139         getNextToken();
2140         if (token == TokenNameinclude
2141           || token == TokenNameinclude_once
2142           || token == TokenNamerequire
2143           || token == TokenNamerequire_once) {
2144           statement(TokenNameAT);
2145         } else {
2146           postfixExpression(); //  castExpression();
2147         }
2148         break;
2149       case TokenNameAND :
2150         getNextToken();
2151         castExpression();
2152         break;
2153       case TokenNameMULTIPLY :
2154         getNextToken();
2155         castExpression();
2156         break;
2157       case TokenNamePLUS :
2158         getNextToken();
2159         castExpression();
2160         break;
2161       case TokenNameMINUS :
2162         getNextToken();
2163         castExpression();
2164         break;
2165       case TokenNameTWIDDLE :
2166         getNextToken();
2167         castExpression();
2168         break;
2169       case TokenNameNOT :
2170         getNextToken();
2171         castExpression();
2172         break;
2173       default :
2174         postfixExpression();
2175     }
2176   }
2177
2178   private void castExpression() throws CoreException {
2179     //    if (token == TokenNameARGOPEN) {
2180     //      getNextToken();
2181     //      typeName();
2182     //      if (token != TokenNameARGCLOSE) {
2183     //        throwSyntaxError(") expected after cast-expression.");
2184     //      }
2185     //      getNextToken();
2186     //    }
2187     unaryExpression();
2188   }
2189
2190   private void assignExpression() throws CoreException {
2191     castExpression();
2192     if (token == TokenNameEQUAL) { // =
2193       getNextToken();
2194       logicalinclusiveorExpression();
2195     } else if (token == TokenNameDOT_EQUAL) { // .=
2196       getNextToken();
2197       logicalinclusiveorExpression();
2198     } else if (token == TokenNameEQUAL_GREATER) { // =>
2199       getNextToken();
2200       logicalinclusiveorExpression();
2201     } else if (token == TokenNamePLUS_EQUAL) { // +=
2202       getNextToken();
2203       logicalinclusiveorExpression();
2204     } else if (token == TokenNameMINUS_EQUAL) { // -=
2205       getNextToken();
2206       logicalinclusiveorExpression();
2207     } else if (token == TokenNameMULTIPLY_EQUAL) { // *=
2208       getNextToken();
2209       logicalinclusiveorExpression();
2210     } else if (token == TokenNameDIVIDE_EQUAL) { // *=
2211       getNextToken();
2212       logicalinclusiveorExpression();
2213     } else if (token == TokenNameREMAINDER_EQUAL) { // %=
2214       getNextToken();
2215       logicalinclusiveorExpression();
2216     } else if (token == TokenNameAND_EQUAL) { // &=
2217       getNextToken();
2218       logicalinclusiveorExpression();
2219     } else if (token == TokenNameOR_EQUAL) { // |=
2220       getNextToken();
2221       logicalinclusiveorExpression();
2222     } else if (token == TokenNameXOR_EQUAL) { // ^=
2223       getNextToken();
2224       logicalinclusiveorExpression();
2225     } else if (token == TokenNameLEFT_SHIFT_EQUAL) { // <<=
2226       getNextToken();
2227       logicalinclusiveorExpression();
2228     } else if (token == TokenNameRIGHT_SHIFT_EQUAL) { // >>=
2229       getNextToken();
2230       logicalinclusiveorExpression();
2231     } else if (token == TokenNameTWIDDLE_EQUAL) { // ~=
2232       getNextToken();
2233       logicalinclusiveorExpression();
2234     }
2235   }
2236
2237   private void multiplicativeExpression() throws CoreException {
2238     do {
2239       assignExpression();
2240       if (token != TokenNameMULTIPLY && token != TokenNameDIVIDE && token != TokenNameREMAINDER) {
2241         return;
2242       }
2243       getNextToken();
2244     } while (true);
2245   }
2246
2247   private void concatenationExpression() throws CoreException {
2248     do {
2249       multiplicativeExpression();
2250       if (token != TokenNameDOT) {
2251         return;
2252       }
2253       getNextToken();
2254     } while (true);
2255   }
2256
2257   private void additiveExpression() throws CoreException {
2258     do {
2259       concatenationExpression();
2260       if (token != TokenNamePLUS && token != TokenNameMINUS) {
2261         return;
2262       }
2263       getNextToken();
2264     } while (true);
2265   }
2266
2267   private void shiftExpression() throws CoreException {
2268     do {
2269       additiveExpression();
2270       if (token != TokenNameLEFT_SHIFT && token != TokenNameRIGHT_SHIFT) {
2271         return;
2272       }
2273       getNextToken();
2274     } while (true);
2275   }
2276
2277   private void relationalExpression() throws CoreException {
2278     do {
2279       shiftExpression();
2280       if (token != TokenNameLESS && token != TokenNameGREATER && token != TokenNameLESS_EQUAL && token != TokenNameGREATER_EQUAL) {
2281         return;
2282       }
2283       getNextToken();
2284     } while (true);
2285   }
2286
2287   private void identicalExpression() throws CoreException {
2288     do {
2289       relationalExpression();
2290       if (token != TokenNameEQUAL_EQUAL_EQUAL && token != TokenNameNOT_EQUAL_EQUAL) {
2291         return;
2292       }
2293       getNextToken();
2294     } while (true);
2295   }
2296
2297   private void equalityExpression() throws CoreException {
2298     do {
2299       identicalExpression();
2300       if (token != TokenNameEQUAL_EQUAL && token != TokenNameNOT_EQUAL) {
2301         return;
2302       }
2303       getNextToken();
2304     } while (true);
2305   }
2306
2307   private void ternaryExpression() throws CoreException {
2308     equalityExpression();
2309     if (token == TokenNameQUESTION) {
2310       getNextToken();
2311       expression();
2312       if (token == TokenNameCOLON) {
2313         getNextToken();
2314         expression();
2315       } else {
2316         throwSyntaxError("':' expected in ternary operator '? :'.");
2317       }
2318     }
2319   }
2320
2321   private void andExpression() throws CoreException {
2322     do {
2323       ternaryExpression();
2324       if (token != TokenNameAND) {
2325         return;
2326       }
2327       getNextToken();
2328     } while (true);
2329   }
2330
2331   private void exclusiveorExpression() throws CoreException {
2332     do {
2333       andExpression();
2334       if (token != TokenNameXOR) {
2335         return;
2336       }
2337       getNextToken();
2338     } while (true);
2339   }
2340
2341   private void inclusiveorExpression() throws CoreException {
2342     do {
2343       exclusiveorExpression();
2344       if (token != TokenNameOR) {
2345         return;
2346       }
2347       getNextToken();
2348     } while (true);
2349   }
2350
2351   private void booleanandExpression() throws CoreException {
2352     do {
2353       inclusiveorExpression();
2354       if (token != TokenNameAND_AND) {
2355         return;
2356       }
2357       getNextToken();
2358     } while (true);
2359   }
2360
2361   private void booleanorExpression() throws CoreException {
2362     do {
2363       booleanandExpression();
2364       if (token != TokenNameOR_OR) {
2365         return;
2366       }
2367       getNextToken();
2368     } while (true);
2369   }
2370
2371   private void logicalandExpression() throws CoreException {
2372     do {
2373       booleanorExpression();
2374       if (token != TokenNameAND) {
2375         return;
2376       }
2377       getNextToken();
2378     } while (true);
2379   }
2380
2381   private void logicalexclusiveorExpression() throws CoreException {
2382     do {
2383       logicalandExpression();
2384       if (token != TokenNameXOR) {
2385         return;
2386       }
2387       getNextToken();
2388     } while (true);
2389   }
2390
2391   private void logicalinclusiveorExpression() throws CoreException {
2392     do {
2393       logicalexclusiveorExpression();
2394       if (token != TokenNameOR) {
2395         return;
2396       }
2397       getNextToken();
2398     } while (true);
2399   }
2400
2401   //  public void assignmentExpression() {
2402   //    if (token == TokenNameVARIABLE) {
2403   //      getNextToken();
2404   //      if (token == TokenNameSET) {
2405   //        getNextToken();
2406   //        logicalinclusiveorExpression();
2407   //      }
2408   //    } else {
2409   //      logicalinclusiveorExpression();
2410   //    }
2411   //  }
2412
2413   private void variableList() throws CoreException {
2414     do {
2415       variable();
2416       if (token == TokenNameCOMMA) {
2417         getNextToken();
2418       } else {
2419         break;
2420       }
2421     } while (true);
2422   }
2423
2424   private void variable() throws CoreException {
2425     if (token == TokenNameDOLLAR_LBRACE) {
2426       getNextToken();
2427       expression();
2428       ;
2429       if (token != TokenNameRBRACE) {
2430         throwSyntaxError("'}' expected after indirect variable token '${'.");
2431       }
2432       getNextToken();
2433     } else {
2434       if (token == TokenNameVariable) {
2435         getNextToken();
2436         if (token == TokenNameLBRACKET) {
2437           getNextToken();
2438           expression();
2439           if (token != TokenNameRBRACKET) {
2440             throwSyntaxError("']' expected in variable-list.");
2441           }
2442           getNextToken();
2443         } else if (token == TokenNameEQUAL) {
2444           getNextToken();
2445           constant();
2446         }
2447       } else {
2448         throwSyntaxError("$-variable expected in variable-list.");
2449       }
2450     }
2451   }
2452
2453   /**
2454    * It will look for a value (after a '=' for example)
2455    * @throws CoreException
2456    */
2457   private void constant() throws CoreException {
2458     //   String ident;
2459     switch (token) {
2460       case TokenNamePLUS :
2461         getNextToken();
2462         switch (token) {
2463           case TokenNameDoubleLiteral :
2464             getNextToken();
2465             break;
2466           case TokenNameIntegerLiteral :
2467             getNextToken();
2468             break;
2469           default :
2470             throwSyntaxError("Constant expected after '+' presign.");
2471         }
2472         break;
2473       case TokenNameMINUS :
2474         getNextToken();
2475         switch (token) {
2476           case TokenNameDoubleLiteral :
2477             getNextToken();
2478             break;
2479           case TokenNameIntegerLiteral :
2480             getNextToken();
2481             break;
2482           default :
2483             throwSyntaxError("Constant expected after '-' presign.");
2484         }
2485         break;
2486       case TokenNamenull :
2487         getNextToken();
2488         break;
2489       case TokenNamefalse :
2490         getNextToken();
2491         break;
2492       case TokenNametrue :
2493         getNextToken();
2494         break;
2495       case TokenNameIdentifier :
2496         //   ident = identifier;
2497         char[] ident = scanner.getCurrentIdentifierSource();
2498         getNextToken();
2499         if (token == TokenNameLPAREN) {
2500           getNextToken();
2501           if (token != TokenNameRPAREN) {
2502             expressionList();
2503             if (token != TokenNameRPAREN) {
2504               throwSyntaxError("')' expected after identifier '" + new String(ident) + "' in postfix-expression.");
2505             }
2506           }
2507           getNextToken();
2508         }
2509         break;
2510       case TokenNameStringLiteral :
2511         getNextToken();
2512         break;
2513       case TokenNameStringConstant :
2514         getNextToken();
2515         break;
2516       case TokenNameStringInterpolated :
2517         getNextToken();
2518         break;
2519       case TokenNameDoubleLiteral :
2520         getNextToken();
2521         break;
2522       case TokenNameIntegerLiteral :
2523         getNextToken();
2524         break;
2525       default :
2526         throwSyntaxError("Constant expected.");
2527     }
2528   }
2529
2530 }