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