Some refactor to use the PHPSegmentWithChildren instead of PHPClassDeclaration
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / phpparser / 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.phpparser;
12
13 import java.text.MessageFormat;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.Hashtable;
17
18 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
19 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
20 import net.sourceforge.phpeclipse.phpeditor.PHPString;
21 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.resources.IMarker;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.jface.preference.IPreferenceStore;
27 import org.eclipse.ui.texteditor.MarkerUtilities;
28
29 public class PHPParser extends PHPKeywords {
30   // strings for external parser call
31   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
32   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
33
34   public static final int ERROR = 2;
35   public static final int WARNING = 1;
36   public static final int INFO = 0;
37   private IFile fileToParse;
38   private ArrayList phpList;
39
40   private int currentPHPString;
41   private boolean phpEnd;
42
43   private static HashMap keywordMap = null;
44   private String str;
45
46   // current character
47   char ch;
48   // current token
49   int token;
50
51   // row counter for syntax errors:
52   int rowCount;
53   // column counter for syntax errors:
54   int columnCount;
55
56   int chIndx;
57
58   // current identifier
59   String identifier;
60
61   Long longNumber;
62   Double doubleNumber;
63
64   private String stringValue;
65
66   /** Contains the current expression. */
67   private StringBuffer expression;
68
69   private boolean phpMode;
70
71   final static int TT_EOF = 0;
72   final static int TT_UNDEFINED = 1;
73   final static int TT_HTML = 2;
74
75   final static int TT_MOD = 30;
76   final static int TT_NOT = 31;
77   final static int TT_DOT = 32;
78   final static int TT_POW = 33;
79   final static int TT_DIV = 34;
80   final static int TT_MULTIPLY = 35;
81   final static int TT_SUBTRACT = 36;
82   final static int TT_ADD = 37;
83   final static int TT_EQUAL = 38;
84   final static int TT_UNEQUAL = 39;
85   final static int TT_GREATER = 40;
86   final static int TT_GREATEREQUAL = 41;
87   final static int TT_LESS = 42;
88   final static int TT_LESSEQUAL = 43;
89   final static int TT_AND = 44;
90   final static int TT_OR = 45;
91   final static int TT_HASH = 46;
92   final static int TT_DDOT = 47;
93   final static int TT_DOTASSIGN = 48;
94
95   final static int TT_ASSIGN = 49;
96   final static int TT_REF = 50;
97   final static int TT_FOREACH = 51;
98   final static int TT_AMPERSAND = 52;
99   final static int TT_DOLLARLISTOPEN = 53;
100   final static int TT_TILDE = 54;
101   final static int TT_TILDEASSIGN = 55;
102   final static int TT_MODASSIGN = 56;
103   final static int TT_POWASSIGN = 57;
104   final static int TT_RSHIFTASSIGN = 58;
105   final static int TT_LSHIFTASSIGN = 59;
106   final static int TT_ANDASSIGN = 60;
107   final static int TT_QUESTIONMARK = 61;
108   final static int TT_DDOT2 = 62;
109   final static int TT_AT = 63;
110   // final static int TT_HEREDOC = 64;
111
112   final static int TT_DOLLAROPEN = 127;
113   final static int TT_ARGOPEN = 128;
114   final static int TT_ARGCLOSE = 129;
115   final static int TT_LISTOPEN = 130;
116   final static int TT_LISTCLOSE = 131;
117   final static int TT_PARTOPEN = 132;
118   final static int TT_PARTCLOSE = 133;
119   final static int TT_COMMA = 134;
120
121   final static int TT_STRING = 136;
122   final static int TT_IDENTIFIER = 138;
123   final static int TT_DIGIT = 139;
124   final static int TT_SEMICOLON = 140;
125   final static int TT_SLOT = 141;
126   final static int TT_SLOTSEQUENCE = 142;
127   final static int TT_DECREMENT = 144;
128   final static int TT_INCREMENT = 145;
129   final static int TT_ADDTO = 146;
130   final static int TT_DIVIDEBY = 147;
131   final static int TT_SUBTRACTFROM = 148;
132   final static int TT_TIMESBY = 149;
133   final static int TT_VARIABLE = 150;
134   final static int TT_INT_NUMBER = 151;
135   final static int TT_DOUBLE_NUMBER = 152;
136   final static int TT_INTERPOLATED_STRING = 153;
137   final static int TT_STRING_CONSTANT = 154;
138
139   final static int TT_LSHIFT = 155;
140   final static int TT_RSHIFT = 156;
141   final static int TT_EX_EQUAL = 157;
142   final static int TT_EX_UNEQUAL = 158;
143   final static int TT_LINE = 159;
144   //  final static int TT_AT = 153; // @
145   /**
146    *  Class Constructor.
147    *
148    *@param  s
149    *@param  sess  Description of Parameter
150    *@see
151    */
152   public PHPParser(IFile fileToParse) {
153     if (keywordMap == null) {
154       keywordMap = new HashMap();
155       for (int i = 0; i < PHP_KEYWORS.length; i++) {
156         keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
157       }
158     }
159     this.currentPHPString = 0;
160     this.fileToParse = fileToParse;
161     this.phpList = null;
162     this.str = "";
163     this.token = TT_EOF;
164     this.chIndx = 0;
165     this.rowCount = 1;
166     this.columnCount = 0;
167     this.phpEnd = false;
168
169     //   getNextToken();
170   }
171
172   /**
173    * Create marker for the parse error
174    */
175   private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
176     setMarker(fileToParse, message, lineNumber, errorLevel);
177   }
178
179   public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
180     if (file != null) {
181       Hashtable attributes = new Hashtable();
182       MarkerUtilities.setMessage(attributes, message);
183       switch (errorLevel) {
184         case ERROR :
185           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
186           break;
187         case WARNING :
188           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
189           break;
190         case INFO :
191           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
192           break;
193       }
194       MarkerUtilities.setLineNumber(attributes, lineNumber);
195       MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
196     }
197   }
198
199   private void throwSyntaxError(String error) {
200
201     if (str.length() < chIndx) {
202       chIndx--;
203     }
204     // read until end-of-line
205     int eol = chIndx;
206     while (str.length() > eol) {
207       ch = str.charAt(eol++);
208       if (ch == '\n') {
209         eol--;
210         break;
211       }
212     }
213     throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
214   }
215
216   private void throwSyntaxError(String error, int startRow) {
217
218     throw new SyntaxError(startRow, 0, " ", error);
219   }
220
221   /**
222    *  Method Declaration.
223    *
224    *@see
225    */
226   private void getChar() {
227     if (str.length() > chIndx) {
228       ch = str.charAt(chIndx++);
229
230       return;
231     }
232
233     chIndx = str.length() + 1;
234     ch = ' ';
235     //  token = TT_EOF;
236     phpEnd = true;
237   }
238
239   private void getNextToken_OldVersion() throws CoreException {
240     phpEnd = false;
241
242     while (str.length() > chIndx) {
243       ch = str.charAt(chIndx++);
244       token = TT_UNDEFINED;
245       if (ch == '\n') {
246         rowCount++;
247         columnCount = chIndx;
248         continue; // while loop
249       }
250       if (str.length() == chIndx) {
251         phpEnd = true;
252       }
253       if (!Character.isWhitespace(ch)) {
254         if (ch == '$') {
255           if (str.length() > chIndx) {
256             if (str.charAt(chIndx) == '{') {
257               chIndx++;
258               token = TT_DOLLAROPEN;
259               return;
260             }
261           }
262           getIdentifier();
263           return;
264         }
265         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
266           getIdentifier();
267           return;
268         }
269         if (ch >= '0' && ch <= '9') {
270           getNumber();
271           return;
272         }
273         if (ch == '/') {
274           if (str.length() > chIndx) {
275             if (str.charAt(chIndx) == '/') {
276               chIndx++;
277               // read comment until end of line:
278               while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
279                 chIndx++;
280               }
281               continue;
282             } else if (str.charAt(chIndx) == '*') {
283               chIndx++;
284               // multi line comment:
285               while (str.length() > chIndx) {
286                 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
287                   chIndx += 2;
288                   break;
289                 }
290                 ch = str.charAt(chIndx++);
291                 if (ch == '\n') {
292                   rowCount++;
293                   columnCount = chIndx;
294                 }
295               }
296               continue;
297             }
298           }
299         } else if (ch == '#') {
300           // read comment until end of line:
301           while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
302             chIndx++;
303           }
304           continue;
305         } else if (ch == '"') {
306           // read string until end
307           boolean openString = true;
308           while (str.length() > chIndx) {
309             ch = str.charAt(chIndx++);
310             if (ch == '\\') {
311               if (str.length() > chIndx) {
312                 ch = str.charAt(chIndx++);
313               }
314             } else if (ch == '"') {
315               openString = false;
316               break;
317             } else if (ch == '\n') {
318               rowCount++;
319               columnCount = chIndx;
320             }
321           }
322           if (openString) {
323             throwSyntaxError("Open string character '\"' at end of file.");
324           }
325           token = TT_INTERPOLATED_STRING;
326           return;
327         } else if (ch == '\'') {
328           // read string until end
329           boolean openString = true;
330           int startRow = rowCount;
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.", startRow);
347           }
348           token = TT_STRING_CONSTANT;
349           return;
350         } else if (ch == '`') {
351           // read string until end
352           boolean openString = true;
353           int startRow = rowCount;
354           while (str.length() > chIndx) {
355             ch = str.charAt(chIndx++);
356             if (ch == '\\') {
357               if (str.length() > chIndx) {
358                 ch = str.charAt(chIndx++);
359               }
360             } else if (ch == '`') {
361               openString = false;
362               break;
363             } else if (ch == '\n') {
364               rowCount++;
365               columnCount = chIndx;
366             }
367           }
368           if (openString) {
369             throwSyntaxError("Open string character \"`\" at end of file.", startRow);
370           }
371           token = TT_STRING_CONSTANT;
372           return;
373         }
374
375         switch (ch) {
376
377           case '(' :
378             token = TT_ARGOPEN;
379
380             break;
381           case ')' :
382             token = TT_ARGCLOSE;
383
384             break;
385           case '{' :
386             token = TT_LISTOPEN;
387
388             break;
389           case '}' :
390             token = TT_LISTCLOSE;
391
392             break;
393           case '[' :
394             token = TT_PARTOPEN;
395
396             break;
397           case ']' :
398             token = TT_PARTCLOSE;
399
400             break;
401           case ',' :
402             token = TT_COMMA;
403
404             break;
405           case '?' :
406             token = TT_QUESTIONMARK;
407             break;
408           case '@' :
409             token = TT_AT;
410             break;
411           case '~' :
412             token = TT_TILDE;
413             if (str.length() > chIndx) {
414               if (str.charAt(chIndx) == '=') {
415                 chIndx++;
416                 token = TT_TILDEASSIGN;
417
418                 break;
419               }
420             }
421             break;
422           case '.' :
423             token = TT_DOT;
424             if (str.length() > chIndx) {
425               if (str.charAt(chIndx) == '=') {
426                 chIndx++;
427                 token = TT_DOTASSIGN;
428
429                 break;
430               }
431             }
432
433             break;
434           case '"' :
435             token = TT_STRING;
436
437             break;
438           case '%' :
439             token = TT_MOD;
440             if (str.length() > chIndx) {
441               if (str.charAt(chIndx) == '=') {
442                 chIndx++;
443                 token = TT_MODASSIGN;
444
445                 break;
446               }
447             }
448             break;
449           case ';' :
450             token = TT_SEMICOLON;
451
452             break;
453           case '^' :
454             token = TT_POW;
455             if (str.length() > chIndx) {
456               if (str.charAt(chIndx) == '=') {
457                 chIndx++;
458                 token = TT_POWASSIGN;
459
460                 break;
461               }
462             }
463             break;
464           case '/' :
465             token = TT_DIV;
466
467             if (str.length() > chIndx) {
468               if (str.charAt(chIndx) == '=') {
469                 chIndx++;
470                 token = TT_DIVIDEBY;
471
472                 break;
473               }
474             }
475
476             break;
477           case '*' :
478             token = TT_MULTIPLY;
479             if (str.length() > chIndx) {
480               if (str.charAt(chIndx) == '*') {
481                 chIndx++;
482                 token = TT_POW;
483
484                 break;
485               }
486               if (str.charAt(chIndx) == '=') {
487                 chIndx++;
488                 token = TT_TIMESBY;
489
490                 break;
491               }
492             }
493
494             break;
495           case '+' :
496             token = TT_ADD;
497             if (str.length() > chIndx) {
498               if (str.charAt(chIndx) == '+') {
499                 chIndx++;
500                 token = TT_INCREMENT;
501
502                 break;
503               }
504               if (str.charAt(chIndx) == '=') {
505                 chIndx++;
506                 token = TT_ADDTO;
507
508                 break;
509               }
510             }
511             break;
512           case '-' :
513             token = TT_SUBTRACT;
514             if (str.length() > chIndx) {
515               if (str.charAt(chIndx) == '-') {
516                 chIndx++;
517                 token = TT_DECREMENT;
518
519                 break;
520               }
521               if (str.charAt(chIndx) == '=') {
522                 chIndx++;
523                 token = TT_SUBTRACTFROM;
524
525                 break;
526               }
527               if (str.charAt(chIndx) == '>') {
528                 chIndx++;
529                 token = TT_REF;
530
531                 break;
532               }
533             }
534
535             break;
536           case '=' :
537             token = TT_ASSIGN;
538
539             if (str.length() > chIndx) {
540               ch = str.charAt(chIndx);
541
542               if (ch == '=') {
543                 chIndx++;
544                 token = TT_EQUAL;
545                 if (str.length() > chIndx) {
546                   ch = str.charAt(chIndx);
547
548                   if (ch == '=') {
549                     chIndx++;
550                     token = TT_EX_EQUAL;
551                   }
552                 }
553                 break;
554               }
555               if (ch == '>') {
556                 chIndx++;
557                 token = TT_FOREACH;
558
559                 break;
560               }
561             }
562
563             break;
564           case '!' :
565             token = TT_NOT;
566
567             if (str.length() > chIndx) {
568               if (str.charAt(chIndx) == '=') {
569                 chIndx++;
570                 token = TT_UNEQUAL;
571                 if (str.length() > chIndx) {
572                   ch = str.charAt(chIndx);
573
574                   if (ch == '=') {
575                     chIndx++;
576                     token = TT_EX_UNEQUAL;
577                   }
578                 }
579                 break;
580               }
581             }
582
583             break;
584           case '>' :
585             token = TT_GREATER;
586
587             if (str.length() > chIndx) {
588               if (str.charAt(chIndx) == '=') {
589                 chIndx++;
590                 token = TT_GREATEREQUAL;
591                 break;
592               }
593               if (str.charAt(chIndx) == '>') {
594                 chIndx++;
595                 token = TT_RSHIFT;
596                 if (str.length() > chIndx) {
597                   if (str.charAt(chIndx) == '=') {
598                     chIndx++;
599                     token = TT_RSHIFTASSIGN;
600                     break;
601                   }
602                 }
603                 break;
604               }
605             }
606
607             break;
608           case '<' :
609             token = TT_LESS;
610
611             if (str.length() > chIndx) {
612               if (str.charAt(chIndx) == '=') {
613                 chIndx++;
614                 token = TT_LESSEQUAL;
615
616                 break;
617               }
618               if (str.charAt(chIndx) == '<') {
619                 chIndx++;
620                 token = TT_LSHIFT;
621                 if (str.charAt(chIndx) == '<') {
622                   // heredoc
623                   int startRow = rowCount;
624                   if (str.length() > chIndx) {
625
626                     ch = str.charAt(++chIndx);
627                     if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
628                       chIndx++;
629                       getIdentifier();
630                       token = TT_STRING_CONSTANT;
631                       while (str.length() > chIndx) {
632                         ch = str.charAt(chIndx++);
633                         if (ch == '\n') {
634                           if (str.length() >= chIndx + identifier.length()) {
635                             if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
636                               chIndx += identifier.length();
637                               return;
638                             }
639                           }
640                         }
641                       }
642                     }
643                   }
644                   throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
645                 } else if (str.charAt(chIndx) == '=') {
646                   chIndx++;
647                   token = TT_LSHIFTASSIGN;
648                   break;
649                 }
650                 break;
651               }
652             }
653
654             break;
655
656           case '|' :
657             token = TT_LINE;
658
659             if (str.length() > chIndx) {
660               if (str.charAt(chIndx) == '|') {
661                 chIndx++;
662                 token = TT_OR;
663
664                 break;
665               }
666             }
667
668             break;
669           case '&' :
670             token = TT_AMPERSAND;
671             if (str.length() > chIndx) {
672               if (str.charAt(chIndx) == '&') {
673                 chIndx++;
674                 token = TT_AND;
675                 break;
676               }
677               if (str.charAt(chIndx) == '=') {
678                 chIndx++;
679                 token = TT_ANDASSIGN;
680                 break;
681               }
682               break;
683             }
684
685             break;
686           case ':' :
687             token = TT_DDOT;
688             if (str.length() > chIndx) {
689               if (str.charAt(chIndx) == ':') {
690                 chIndx++;
691                 token = TT_DDOT2;
692               }
693             }
694             break;
695           case '#' :
696             token = TT_HASH;
697
698             break;
699             //          case '@' :
700             //            token = TT_AT;
701             //
702             //            break;
703           default :
704             throwSyntaxError("unexpected character: '" + ch + "'");
705         }
706
707         if (token == TT_UNDEFINED) {
708           throwSyntaxError("token not found");
709         }
710
711         return;
712       }
713     }
714
715     chIndx = str.length() + 1;
716     ch = ' ';
717     token = TT_EOF;
718     phpEnd = true;
719     PHPString temp;
720     if (phpList != null) {
721       if (currentPHPString < phpList.size()) {
722         token = TT_UNDEFINED;
723         temp = (PHPString) phpList.get(currentPHPString++);
724         this.str = temp.getPHPString();
725         this.token = TT_EOF;
726         this.chIndx = 0;
727         this.rowCount = temp.getLineNumber();
728         this.columnCount = 0;
729         getNextToken();
730         phpEnd = true;
731       } else {
732         token = TT_UNDEFINED;
733         return;
734       }
735     }
736   }
737   /**
738    * gets the next token from input
739    */
740   private void getNextToken() throws CoreException {
741     boolean phpFound = false;
742     char ch2;
743
744     phpEnd = false;
745     try {
746       if (!phpMode) {
747
748         while (str.length() > chIndx) {
749           token = TT_UNDEFINED;
750           ch = str.charAt(chIndx++);
751
752           if (ch == '\n') {
753             rowCount++;
754           }
755           if (ch == '<') {
756             ch2 = str.charAt(chIndx++);
757             if (ch2 == '?') {
758               ch2 = str.charAt(chIndx++);
759               if (Character.isWhitespace(ch2)) {
760                 // php start
761                 phpMode = true;
762                 phpFound = true;
763                 break;
764               } else if (ch2 == 'p') {
765                 ch2 = str.charAt(chIndx++);
766                 if (ch2 == 'h') {
767                   ch2 = str.charAt(chIndx++);
768                   if (ch2 == 'p') {
769                     phpMode = true;
770                     phpFound = true;
771                     break;
772                   }
773                   chIndx--;
774                 }
775                 chIndx--;
776               } else if (ch2 == 'P') {
777                 ch2 = str.charAt(chIndx++);
778                 if (ch2 == 'H') {
779                   ch2 = str.charAt(chIndx++);
780                   if (ch2 == 'P') {
781                     phpMode = true;
782                     phpFound = true;
783                     break;
784                   }
785                   chIndx--;
786                 }
787                 chIndx--;
788               }
789               chIndx--;
790             }
791             chIndx--;
792           }
793         }
794
795       }
796
797       if (phpMode) {
798         while (str.length() > chIndx) {
799           ch = str.charAt(chIndx++);
800           token = TT_UNDEFINED;
801           if (ch == '\n') {
802             rowCount++;
803             columnCount = chIndx;
804             continue; // while loop
805           }
806           if (str.length() == chIndx) {
807             phpEnd = true;
808           }
809           if (!Character.isWhitespace(ch)) {
810             if (ch == '$') {
811               if (str.length() > chIndx) {
812                 if (str.charAt(chIndx) == '{') {
813                   chIndx++;
814                   token = TT_DOLLAROPEN;
815                   return;
816                 }
817               }
818               getIdentifier();
819               return;
820             }
821             if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
822               getIdentifier();
823               return;
824             }
825             if (ch >= '0' && ch <= '9') {
826               getNumber();
827               return;
828             }
829             if (ch == '/') {
830               if (str.length() > chIndx) {
831                 if (str.charAt(chIndx) == '/') {
832                   ch = '/';
833                   chIndx++;
834                   // read comment until end of line:
835                   while ((str.length() > chIndx) && (ch != '\n')) {
836                     ch = str.charAt(chIndx++);
837                     if (ch == '?') {
838                       ch2 = str.charAt(chIndx);
839                       if (ch2 == '>') {
840                         chIndx++;
841                         token = TT_HTML;
842                         // php end
843                         phpMode = false;
844                         phpEnd = true;
845                         return;
846                       }
847                     }
848                   }
849                   rowCount++;
850                   continue;
851
852                 } else if (str.charAt(chIndx) == '*') {
853                   chIndx++;
854                   // multi line comment:
855                   while (str.length() > chIndx) {
856                     if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
857                       chIndx += 2;
858                       break;
859                     }
860                     ch = str.charAt(chIndx++);
861                     if (ch == '\n') {
862                       rowCount++;
863                       columnCount = chIndx;
864                     }
865                   }
866                   continue;
867                 }
868               }
869             } else if (ch == '#') {
870               // read comment until end of line:
871               while ((str.length() > chIndx) && (ch != '\n')) {
872                 ch = str.charAt(chIndx++);
873                 if (ch == '?') {
874                   ch2 = str.charAt(chIndx);
875                   if (ch2 == '>') {
876                     chIndx++;
877                     token = TT_HTML;
878                     // php end
879                     phpMode = false;
880                     phpEnd = true;
881                     return;
882                   }
883                 }
884               }
885               rowCount++;
886               continue;
887
888             } else if (ch == '"') {
889               getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
890               return;
891             } else if (ch == '\'') {
892               getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
893               return;
894             } else if (ch == '`') {
895               getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
896               setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
897               return;
898             }
899
900             switch (ch) {
901
902               case '(' :
903                 token = TT_ARGOPEN;
904
905                 break;
906               case ')' :
907                 token = TT_ARGCLOSE;
908
909                 break;
910               case '{' :
911                 token = TT_LISTOPEN;
912
913                 break;
914               case '}' :
915                 token = TT_LISTCLOSE;
916
917                 break;
918               case '[' :
919                 token = TT_PARTOPEN;
920
921                 break;
922               case ']' :
923                 token = TT_PARTCLOSE;
924
925                 break;
926               case ',' :
927                 token = TT_COMMA;
928
929                 break;
930               case '?' :
931                 token = TT_QUESTIONMARK;
932                 if (str.length() > chIndx) {
933                   if (str.charAt(chIndx) == '>') {
934                     chIndx++;
935                     token = TT_HTML;
936                     // php end
937                     phpMode = false;
938                     phpEnd = true;
939                     break;
940                   }
941                 }
942
943                 break;
944               case '@' :
945                 token = TT_AT;
946                 break;
947               case '~' :
948                 token = TT_TILDE;
949                 if (str.length() > chIndx) {
950                   if (str.charAt(chIndx) == '=') {
951                     chIndx++;
952                     token = TT_TILDEASSIGN;
953
954                     break;
955                   }
956                 }
957                 break;
958               case '.' :
959                 token = TT_DOT;
960                 if (str.length() > chIndx) {
961                   if (str.charAt(chIndx) == '=') {
962                     chIndx++;
963                     token = TT_DOTASSIGN;
964
965                     break;
966                   }
967                 }
968
969                 break;
970               case '"' :
971                 token = TT_STRING;
972
973                 break;
974               case '%' :
975                 token = TT_MOD;
976                 if (str.length() > chIndx) {
977                   if (str.charAt(chIndx) == '=') {
978                     chIndx++;
979                     token = TT_MODASSIGN;
980
981                     break;
982                   }
983                 }
984                 break;
985               case ';' :
986                 token = TT_SEMICOLON;
987
988                 break;
989               case '^' :
990                 token = TT_POW;
991                 if (str.length() > chIndx) {
992                   if (str.charAt(chIndx) == '=') {
993                     chIndx++;
994                     token = TT_POWASSIGN;
995
996                     break;
997                   }
998                 }
999                 break;
1000               case '/' :
1001                 token = TT_DIV;
1002
1003                 if (str.length() > chIndx) {
1004                   if (str.charAt(chIndx) == '=') {
1005                     chIndx++;
1006                     token = TT_DIVIDEBY;
1007
1008                     break;
1009                   }
1010                 }
1011
1012                 break;
1013               case '*' :
1014                 token = TT_MULTIPLY;
1015                 if (str.length() > chIndx) {
1016                   if (str.charAt(chIndx) == '*') {
1017                     chIndx++;
1018                     token = TT_POW;
1019
1020                     break;
1021                   }
1022                   if (str.charAt(chIndx) == '=') {
1023                     chIndx++;
1024                     token = TT_TIMESBY;
1025
1026                     break;
1027                   }
1028                 }
1029
1030                 break;
1031               case '+' :
1032                 token = TT_ADD;
1033                 if (str.length() > chIndx) {
1034                   if (str.charAt(chIndx) == '+') {
1035                     chIndx++;
1036                     token = TT_INCREMENT;
1037
1038                     break;
1039                   }
1040                   if (str.charAt(chIndx) == '=') {
1041                     chIndx++;
1042                     token = TT_ADDTO;
1043
1044                     break;
1045                   }
1046                 }
1047                 break;
1048               case '-' :
1049                 token = TT_SUBTRACT;
1050                 if (str.length() > chIndx) {
1051                   if (str.charAt(chIndx) == '-') {
1052                     chIndx++;
1053                     token = TT_DECREMENT;
1054
1055                     break;
1056                   }
1057                   if (str.charAt(chIndx) == '=') {
1058                     chIndx++;
1059                     token = TT_SUBTRACTFROM;
1060
1061                     break;
1062                   }
1063                   if (str.charAt(chIndx) == '>') {
1064                     chIndx++;
1065                     token = TT_REF;
1066
1067                     break;
1068                   }
1069                 }
1070
1071                 break;
1072               case '=' :
1073                 token = TT_ASSIGN;
1074
1075                 if (str.length() > chIndx) {
1076                   ch = str.charAt(chIndx);
1077
1078                   if (ch == '=') {
1079                     chIndx++;
1080                     token = TT_EQUAL;
1081                     if (str.length() > chIndx) {
1082                       ch = str.charAt(chIndx);
1083
1084                       if (ch == '=') {
1085                         chIndx++;
1086                         token = TT_EX_EQUAL;
1087                       }
1088                     }
1089                     break;
1090                   }
1091                   if (ch == '>') {
1092                     chIndx++;
1093                     token = TT_FOREACH;
1094
1095                     break;
1096                   }
1097                 }
1098
1099                 break;
1100               case '!' :
1101                 token = TT_NOT;
1102
1103                 if (str.length() > chIndx) {
1104                   if (str.charAt(chIndx) == '=') {
1105                     chIndx++;
1106                     token = TT_UNEQUAL;
1107                     if (str.length() > chIndx) {
1108                       ch = str.charAt(chIndx);
1109
1110                       if (ch == '=') {
1111                         chIndx++;
1112                         token = TT_EX_UNEQUAL;
1113                       }
1114                     }
1115                     break;
1116                   }
1117                 }
1118
1119                 break;
1120               case '>' :
1121                 token = TT_GREATER;
1122
1123                 if (str.length() > chIndx) {
1124                   if (str.charAt(chIndx) == '=') {
1125                     chIndx++;
1126                     token = TT_GREATEREQUAL;
1127                     break;
1128                   }
1129                   if (str.charAt(chIndx) == '>') {
1130                     chIndx++;
1131                     token = TT_RSHIFT;
1132                     if (str.length() > chIndx) {
1133                       if (str.charAt(chIndx) == '=') {
1134                         chIndx++;
1135                         token = TT_RSHIFTASSIGN;
1136                         break;
1137                       }
1138                     }
1139                     break;
1140                   }
1141                 }
1142
1143                 break;
1144               case '<' :
1145                 token = TT_LESS;
1146
1147                 if (str.length() > chIndx) {
1148                   if (str.charAt(chIndx) == '=') {
1149                     chIndx++;
1150                     token = TT_LESSEQUAL;
1151
1152                     break;
1153                   }
1154                   if (str.charAt(chIndx) == '<') {
1155                     chIndx++;
1156                     token = TT_LSHIFT;
1157                     if (str.charAt(chIndx) == '<') {
1158                       // heredoc
1159                       int startRow = rowCount;
1160                       if (str.length() > chIndx) {
1161
1162                         ch = str.charAt(++chIndx);
1163                         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1164                           chIndx++;
1165                           getIdentifier();
1166                           token = TT_STRING_CONSTANT;
1167                           while (str.length() > chIndx) {
1168                             ch = str.charAt(chIndx++);
1169                             if (ch == '\n') {
1170                               if (str.length() >= chIndx + identifier.length()) {
1171                                 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1172                                   chIndx += identifier.length();
1173                                   return;
1174                                 }
1175                               }
1176                             }
1177                           }
1178                         }
1179                       }
1180                       throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1181                     } else if (str.charAt(chIndx) == '=') {
1182                       chIndx++;
1183                       token = TT_LSHIFTASSIGN;
1184                       break;
1185                     }
1186                     break;
1187                   }
1188                 }
1189
1190                 break;
1191
1192               case '|' :
1193                 token = TT_LINE;
1194
1195                 if (str.length() > chIndx) {
1196                   if (str.charAt(chIndx) == '|') {
1197                     chIndx++;
1198                     token = TT_OR;
1199
1200                     break;
1201                   }
1202                 }
1203
1204                 break;
1205               case '&' :
1206                 token = TT_AMPERSAND;
1207                 if (str.length() > chIndx) {
1208                   if (str.charAt(chIndx) == '&') {
1209                     chIndx++;
1210                     token = TT_AND;
1211                     break;
1212                   }
1213                   if (str.charAt(chIndx) == '=') {
1214                     chIndx++;
1215                     token = TT_ANDASSIGN;
1216                     break;
1217                   }
1218                   break;
1219                 }
1220
1221                 break;
1222               case ':' :
1223                 token = TT_DDOT;
1224                 if (str.length() > chIndx) {
1225                   if (str.charAt(chIndx) == ':') {
1226                     chIndx++;
1227                     token = TT_DDOT2;
1228                   }
1229                 }
1230                 break;
1231               case '#' :
1232                 token = TT_HASH;
1233
1234                 break;
1235                 //          case '@' :
1236                 //            token = TT_AT;
1237                 //
1238                 //            break;
1239               default :
1240                 throwSyntaxError("unexpected character: '" + ch + "'");
1241             }
1242
1243             if (token == TT_UNDEFINED) {
1244               throwSyntaxError("token not found");
1245             }
1246
1247             return;
1248           }
1249         }
1250       }
1251     } catch (StringIndexOutOfBoundsException e) {
1252       // catched from charAt
1253     }
1254
1255     chIndx = str.length() + 1;
1256     ch = ' ';
1257     token = TT_EOF;
1258     phpEnd = true;
1259     //PHPString temp;
1260     //    if (phpList != null) {
1261     //      if (currentPHPString < phpList.size()) {
1262     //        token = TT_UNDEFINED;
1263     //        temp = (PHPString) phpList.get(currentPHPString++);
1264     //        this.str = temp.getPHPString();
1265     //        this.token = TT_EOF;
1266     //        this.chIndx = 0;
1267     //        this.rowCount = temp.getLineNumber();
1268     //        this.columnCount = 0;
1269     //        getNextToken();
1270     //        phpEnd = true;
1271     //      } else {
1272     //        token = TT_UNDEFINED;
1273     //        return;
1274     //      }
1275     //    }
1276   }
1277
1278
1279   private void getIdentifier() {
1280     StringBuffer ident = new StringBuffer();
1281
1282     ident.append(ch);
1283     if (ch == '$') {
1284       getChar();
1285       // attention recursive call:
1286       getIdentifier();
1287       token = TT_VARIABLE;
1288       return;
1289     } else {
1290       token = TT_IDENTIFIER;
1291     }
1292
1293     getChar();
1294     while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1295       ident.append(ch);
1296       getChar();
1297     }
1298     identifier = ident.toString();
1299     chIndx--;
1300
1301     // determine if this identitfer is a keyword
1302     // @todo improve this in future version
1303     Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1304     if (i != null) {
1305       token = i.intValue();
1306     }
1307   }
1308
1309   private void getNumber() {
1310     StringBuffer inum = new StringBuffer();
1311     char dFlag = ' ';
1312     int numFormat = 10;
1313
1314     // save first digit
1315     char firstCh = ch;
1316     inum.append(ch);
1317
1318     getChar();
1319     // determine number conversions:
1320     if (firstCh == '0') {
1321       switch (ch) {
1322         case 'b' :
1323           numFormat = 2;
1324           getChar();
1325           break;
1326         case 'B' :
1327           numFormat = 2;
1328           getChar();
1329           break;
1330         case 'o' :
1331           numFormat = 8;
1332           getChar();
1333           break;
1334         case 'O' :
1335           numFormat = 8;
1336           getChar();
1337           break;
1338         case 'x' :
1339           numFormat = 16;
1340           getChar();
1341           break;
1342         case 'X' :
1343           numFormat = 16;
1344           getChar();
1345           break;
1346       }
1347     }
1348
1349     if (numFormat == 16) {
1350       while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1351         inum.append(ch);
1352         getChar();
1353       }
1354     } else {
1355       while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1356         if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1357           if (ch == '.' && dFlag != ' ') {
1358             break;
1359           }
1360           if ((dFlag == 'E') || (dFlag == 'e')) {
1361             break;
1362           }
1363           dFlag = ch;
1364           inum.append(ch);
1365           getChar();
1366           if ((ch == '-') || (ch == '+')) {
1367             inum.append(ch);
1368             getChar();
1369           }
1370         } else {
1371           inum.append(ch);
1372           getChar();
1373         }
1374       }
1375     }
1376     chIndx--;
1377
1378     try {
1379       if (dFlag != ' ') {
1380         doubleNumber = new Double(inum.toString());
1381         token = TT_DOUBLE_NUMBER;
1382         return;
1383       } else {
1384         longNumber = Long.valueOf(inum.toString(), numFormat);
1385         token = TT_INT_NUMBER;
1386         return;
1387       }
1388
1389     } catch (Throwable e) {
1390       throwSyntaxError("Number format error: " + inum.toString());
1391     }
1392   }
1393
1394   /**
1395    * Get a String.
1396    * @param openChar the opening char ('\'', '"', '`')
1397    * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
1398    * @param errorMsg the error message in case of parse error in the string
1399    */
1400   private void getString(final char openChar, final int typeString, final String errorMsg) {
1401     StringBuffer sBuffer = new StringBuffer();
1402     boolean openString = true;
1403     int startRow = rowCount;
1404     while (str.length() > chIndx) {
1405       ch = str.charAt(chIndx++);
1406       if (ch == '\\') {
1407         sBuffer.append(ch);
1408         if (str.length() > chIndx) {
1409           ch = str.charAt(chIndx++);
1410           sBuffer.append(ch);
1411         }
1412       } else if (ch == openChar) {
1413         openString = false;
1414         break;
1415       } else if (ch == '\n') {
1416         rowCount++;
1417         columnCount = chIndx;
1418       } else {
1419         sBuffer.append(ch);
1420       }
1421     }
1422     if (openString) {
1423       if (typeString == TT_STRING_CONSTANT) {
1424         throwSyntaxError(errorMsg, startRow);
1425       } else {
1426         throwSyntaxError(errorMsg);
1427       }
1428     }
1429     token = typeString;
1430     stringValue = sBuffer.toString();
1431   }
1432
1433   public void htmlParserTester(String input) {
1434     int lineNumber = 1;
1435     int startLineNumber = 1;
1436     int startIndex = 0;
1437     char ch;
1438     char ch2;
1439     boolean phpMode = false;
1440     boolean phpFound = false;
1441
1442     phpList = new ArrayList();
1443     currentPHPString = 0;
1444
1445     try {
1446       int i = 0;
1447       while (i < input.length()) {
1448         ch = input.charAt(i++);
1449         if (ch == '\n') {
1450           lineNumber++;
1451         }
1452         if ((!phpMode) && ch == '<') {
1453           ch2 = input.charAt(i++);
1454           if (ch2 == '?') {
1455             ch2 = input.charAt(i++);
1456             if (Character.isWhitespace(ch2)) {
1457               // php start
1458               phpMode = true;
1459               phpFound = true;
1460               startIndex = i;
1461               startLineNumber = lineNumber;
1462               continue;
1463             } else if (ch2 == 'p') {
1464               ch2 = input.charAt(i++);
1465               if (ch2 == 'h') {
1466                 ch2 = input.charAt(i++);
1467                 if (ch2 == 'p') {
1468                   phpMode = true;
1469                   phpFound = true;
1470                   startIndex = i;
1471                   startLineNumber = lineNumber;
1472                   continue;
1473                 }
1474                 i--;
1475               }
1476               i--;
1477             } else if (ch2 == 'P') {
1478               ch2 = input.charAt(i++);
1479               if (ch2 == 'H') {
1480                 ch2 = input.charAt(i++);
1481                 if (ch2 == 'P') {
1482                   phpMode = true;
1483                   phpFound = true;
1484                   startIndex = i;
1485                   startLineNumber = lineNumber;
1486                   continue;
1487                 }
1488                 i--;
1489               }
1490               i--;
1491             }
1492             i--;
1493           }
1494           i--;
1495         }
1496
1497         if (phpMode) {
1498           if (ch == '/' && i < input.length()) {
1499             ch2 = input.charAt(i++);
1500             if (ch2 == '/') {
1501               while (i < input.length()) {
1502                 ch = input.charAt(i++);
1503                 if (ch == '?' && i < input.length()) {
1504                   ch2 = input.charAt(i++);
1505                   if (ch2 == '>') {
1506                     // php end
1507                     phpMode = false;
1508                     phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1509                     continue;
1510                   }
1511                   i--;
1512                 } else if (ch == '\n') {
1513                   lineNumber++;
1514                   break;
1515                 }
1516               }
1517               continue;
1518             } else if (ch2 == '*') {
1519               // multi-line comment
1520               while (i < input.length()) {
1521                 ch = input.charAt(i++);
1522                 if (ch == '\n') {
1523                   lineNumber++;
1524                 } else if (ch == '*' && i < input.length()) {
1525                   ch2 = input.charAt(i++);
1526                   if (ch2 == '/') {
1527                     break;
1528                   }
1529                   i--;
1530                 }
1531               }
1532               continue;
1533             } else {
1534               i--;
1535             }
1536           } else if (ch == '#') {
1537             while (i < input.length()) {
1538               ch = input.charAt(i++);
1539               if (ch == '?' && i < input.length()) {
1540                 ch2 = input.charAt(i++);
1541                 if (ch2 == '>') {
1542                   // php end
1543                   phpMode = false;
1544                   phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1545                   continue;
1546                 }
1547                 i--;
1548               } else if (ch == '\n') {
1549                 lineNumber++;
1550                 break;
1551               }
1552             }
1553             continue;
1554           } else if (ch == '"') {
1555             ch = ' ';
1556             while (i < input.length()) {
1557               ch = input.charAt(i++);
1558               if (ch == '\n') {
1559                 lineNumber++;
1560               } else if (ch == '\\' && i < input.length()) { // escape
1561                 i++;
1562               } else if (ch == '"') {
1563                 break;
1564               }
1565             }
1566             continue;
1567           } else if (ch == '\'') {
1568             ch = ' ';
1569             while (i < input.length()) {
1570               ch = input.charAt(i++);
1571               if (ch == '\n') {
1572                 lineNumber++;
1573               } else if (ch == '\\' && i < input.length()) { // escape
1574                 i++;
1575               } else if (ch == '\'') {
1576                 break;
1577               }
1578             }
1579             continue;
1580           }
1581
1582           if (ch == '?' && i < input.length()) {
1583             ch2 = input.charAt(i++);
1584             if (ch2 == '>') {
1585               // php end
1586               phpMode = false;
1587               phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1588               continue;
1589             }
1590             i--;
1591           }
1592         }
1593       }
1594
1595       if (!phpFound) {
1596         setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1597       } else {
1598         if (phpMode) {
1599           setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1600           phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1601         }
1602         //        for (int j=0;j<phpList.size();j++) {
1603         //          String temp = ((PHPString)phpList.get(j)).getPHPString();
1604         //          int startIndx = temp.length()-10;
1605         //          if (startIndx<0) {
1606         //            startIndx = 0;
1607         //          }
1608         //          System.out.println(temp.substring(startIndx)+"?>");
1609         //        }
1610         phpParserTester(null, 1);
1611         //        PHPString temp;
1612         //        for(int j=0;j<phpList.size();j++) {
1613         //          temp = (PHPString) phpList.get(j);
1614         //          parser.start(temp.getPHPString(), temp.getLineNumber());
1615         //        }
1616       }
1617     } catch (CoreException e) {
1618     }
1619   }
1620
1621   public void phpParserTester(String s, int rowCount) throws CoreException {
1622     this.str = s;
1623     if (s == null) {
1624       if (phpList.size() != 0) {
1625         this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1626       }
1627     }
1628     this.token = TT_EOF;
1629     this.chIndx = 0;
1630     this.rowCount = rowCount;
1631     this.columnCount = 0;
1632     this.phpEnd = false;
1633     this.phpMode = true;
1634     getNextToken();
1635     do {
1636       try {
1637         if (token != TT_EOF && token != TT_UNDEFINED) {
1638           statementList();
1639         }
1640         if (token != TT_EOF && token != TT_UNDEFINED) {
1641           if (token == TT_ARGCLOSE) {
1642             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1643           }
1644           if (token == TT_LISTCLOSE) {
1645             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1646           }
1647           if (token == TT_PARTCLOSE) {
1648             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1649           }
1650
1651           if (token == TT_ARGOPEN) {
1652             throwSyntaxError("Read character '('; end-of-file not reached.");
1653           }
1654           if (token == TT_LISTOPEN) {
1655             throwSyntaxError("Read character '{';  end-of-file not reached.");
1656           }
1657           if (token == TT_PARTOPEN) {
1658             throwSyntaxError("Read character '[';  end-of-file not reached.");
1659           }
1660
1661           throwSyntaxError("End-of-file not reached.");
1662         }
1663         return;
1664       } catch (SyntaxError err) {
1665         if (s != null) {
1666           throw err;
1667         } else {
1668           setMarker(err.getMessage(), err.getLine(), ERROR);
1669         }
1670         // if an error occured,
1671         // try to find keywords 'class' or 'function'
1672         // to parse the rest of the string
1673         while (token != TT_EOF && token != TT_UNDEFINED) {
1674           if (token == TT_class || token == TT_function) {
1675             break;
1676           }
1677           getNextToken();
1678         }
1679         if (token == TT_EOF || token == TT_UNDEFINED) {
1680           return;
1681         }
1682       }
1683     }
1684     while (true);
1685   }
1686
1687   /**
1688    * Parses a string with php tags
1689    * i.e. '&lt;body&gt; &lt;?php phpinfo() ?&gt; &lt;/body&gt;'
1690    */
1691   public void parse(String s) throws CoreException {
1692     this.str = s;
1693     this.token = TT_EOF;
1694     this.chIndx = 0;
1695     this.rowCount = 1;
1696     this.columnCount = 0;
1697     this.phpEnd = false;
1698     this.phpMode = false;
1699     getNextToken();
1700     do {
1701       try {
1702         if (token != TT_EOF && token != TT_UNDEFINED) {
1703           statementList();
1704         }
1705         if (token != TT_EOF && token != TT_UNDEFINED) {
1706           if (token == TT_ARGCLOSE) {
1707             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1708           }
1709           if (token == TT_LISTCLOSE) {
1710             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1711           }
1712           if (token == TT_PARTCLOSE) {
1713             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1714           }
1715
1716           if (token == TT_ARGOPEN) {
1717             throwSyntaxError("Read character '('; end-of-file not reached.");
1718           }
1719           if (token == TT_LISTOPEN) {
1720             throwSyntaxError("Read character '{';  end-of-file not reached.");
1721           }
1722           if (token == TT_PARTOPEN) {
1723             throwSyntaxError("Read character '[';  end-of-file not reached.");
1724           }
1725
1726           throwSyntaxError("End-of-file not reached.");
1727         }
1728         return;
1729       } catch (SyntaxError sytaxErr1) {
1730         setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1731         try {
1732           // if an error occured,
1733           // try to find keywords 'class' or 'function'
1734           // to parse the rest of the string
1735           while (token != TT_EOF && token != TT_UNDEFINED) {
1736             if (token == TT_class || token == TT_function) {
1737               break;
1738             }
1739             getNextToken();
1740           }
1741           if (token == TT_EOF || token == TT_UNDEFINED) {
1742             return;
1743           }
1744         } catch (SyntaxError sytaxErr2) {
1745           setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1746           return;
1747         }
1748       }
1749     }
1750     while (true);
1751   }
1752
1753   public PHPOutlineInfo parseInfo(Object parent, String s) {
1754     PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1755     //    Stack stack = new Stack();
1756     //    stack.push(outlineInfo.getDeclarations());
1757
1758     this.str = s;
1759     this.token = TT_EOF;
1760     this.chIndx = 0;
1761     this.rowCount = 1;
1762     this.columnCount = 0;
1763     this.phpEnd = false;
1764     this.phpMode = false;
1765
1766     try {
1767       getNextToken();
1768       parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1769     } catch (CoreException e) {
1770     }
1771     return outlineInfo;
1772   }
1773
1774   private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
1775     //   PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1776     PHPSegmentWithChildren temp;
1777     int counter = 0;
1778     String oldIdentifier;
1779     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1780     try {
1781       while (token != TT_EOF && token != TT_UNDEFINED) {
1782         if (token == TT_VARIABLE) {
1783           outlineInfo.addVariable(identifier);
1784           getNextToken();
1785         } else if (token == TT_var) {
1786           getNextToken();
1787           if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1788             getNextToken();
1789             outlineInfo.addVariable(identifier);
1790             if (token != TT_SEMICOLON) {
1791               oldIdentifier = identifier;
1792               getNextToken();
1793               switch (token) {
1794                 case TT_VARIABLE            : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1795                                               break;
1796                 case TT_IDENTIFIER          : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1797                                               break;
1798                 case TT_DOUBLE_NUMBER       : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
1799                                               break;
1800                 case TT_INT_NUMBER          : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
1801                                               break;
1802                 case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1803                                               break;
1804                 case TT_STRING_CONSTANT     : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1805                                               break;
1806                 default                     : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
1807                                               break;
1808               }
1809             } else {
1810               current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1811             }
1812           }
1813         } else if (token == TT_function) {
1814           getNextToken();
1815           if (token == TT_AMPERSAND) {
1816             getNextToken();
1817           }
1818           if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1819             outlineInfo.addVariable(identifier);
1820             temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
1821             current.add(temp);
1822             getNextToken();
1823             parseDeclarations(outlineInfo, temp, true);
1824           }
1825         } else if (token == TT_class) {
1826           getNextToken();
1827           if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
1828             outlineInfo.addVariable(identifier);
1829             temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1830             current.add(temp);
1831             //        stack.push(temp);
1832             getNextToken();
1833
1834             //skip tokens for classname, extends and others until we have the opening '{'
1835             while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1836               getNextToken();
1837             }
1838             parseDeclarations(outlineInfo, temp, true);
1839             //        stack.pop();
1840           }
1841         } else if (token == TT_LISTOPEN) {
1842           getNextToken();
1843           counter++;
1844         } else if (token == TT_LISTCLOSE) {
1845           getNextToken();
1846           --counter;
1847           if (counter == 0 && goBack) {
1848             return;
1849           }
1850         } else if (token == TT_require || token == TT_require_once || token == TT_include || token == TT_include_once) {
1851           expression();
1852           outlineInfo.addVariable(identifier);
1853           current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
1854           getNextToken();
1855         } else {
1856           getNextToken();
1857         }
1858       }
1859     } catch (CoreException e) {
1860     } catch (SyntaxError sytaxErr) {
1861       try {
1862         setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
1863       } catch (CoreException e) {
1864       }
1865     }
1866   }
1867
1868   private void statementList() throws CoreException {
1869     do {
1870       statement();
1871       if ((token == TT_LISTCLOSE)
1872         || (token == TT_case)
1873         || (token == TT_default)
1874         || (token == TT_elseif)
1875         || (token == TT_endif)
1876         || (token == TT_endfor)
1877         || (token == TT_endforeach)
1878         || (token == TT_endwhile)
1879         || (token == TT_endswitch)
1880         || (token == TT_EOF)
1881         || (token == TT_UNDEFINED)) {
1882         return;
1883       }
1884     } while (true);
1885   }
1886
1887   private void compoundStatement() throws CoreException {
1888     // '{' [statement-list] '}'
1889     if (token == TT_LISTOPEN) {
1890       getNextToken();
1891     } else {
1892       throwSyntaxError("'{' expected in compound-statement.");
1893     }
1894     if (token != TT_LISTCLOSE) {
1895       statementList();
1896     }
1897     if (token == TT_LISTCLOSE) {
1898       getNextToken();
1899     } else {
1900       throwSyntaxError("'}' expected in compound-statement.");
1901     }
1902   }
1903
1904   private void statement() throws CoreException {
1905     //   if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1906     String keyword = identifier;
1907     if (token == TT_include || token == TT_include_once) {
1908       getNextToken();
1909       expression();
1910       if (token == TT_SEMICOLON) {
1911         getNextToken();
1912       } else {
1913         if (!phpEnd) {
1914           throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1915         }
1916         getNextToken();
1917       }
1918       return;
1919     } else if (token == TT_require || token == TT_require_once) {
1920       getNextToken();
1921       //constant();
1922       expression();
1923       if (token == TT_SEMICOLON) {
1924         getNextToken();
1925       } else {
1926         if (!phpEnd) {
1927           throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1928         }
1929         getNextToken();
1930       }
1931       return;
1932     } else if (token == TT_if) {
1933       getNextToken();
1934       if (token == TT_ARGOPEN) {
1935         getNextToken();
1936       } else {
1937         throwSyntaxError("'(' expected after 'if' keyword.");
1938       }
1939       expression();
1940       if (token == TT_ARGCLOSE) {
1941         getNextToken();
1942       } else {
1943         throwSyntaxError("')' expected after 'if' condition.");
1944       }
1945       ifStatement();
1946       return;
1947
1948     } else if (token == TT_switch) {
1949       getNextToken();
1950       if (token == TT_ARGOPEN) {
1951         getNextToken();
1952       } else {
1953         throwSyntaxError("'(' expected after 'switch' keyword.");
1954       }
1955       expression();
1956       if (token == TT_ARGCLOSE) {
1957         getNextToken();
1958       } else {
1959         throwSyntaxError("')' expected after 'switch' condition.");
1960       }
1961       switchStatement();
1962       return;
1963     } else if (token == TT_for) {
1964       getNextToken();
1965       if (token == TT_ARGOPEN) {
1966         getNextToken();
1967       } else {
1968         throwSyntaxError("'(' expected after 'for' keyword.");
1969       }
1970       if (token == TT_SEMICOLON) {
1971         getNextToken();
1972       } else {
1973         expressionList();
1974         if (token == TT_SEMICOLON) {
1975           getNextToken();
1976         } else {
1977           throwSyntaxError("';' expected after 'for'.");
1978         }
1979       }
1980       if (token == TT_SEMICOLON) {
1981         getNextToken();
1982       } else {
1983         expressionList();
1984         if (token == TT_SEMICOLON) {
1985           getNextToken();
1986         } else {
1987           throwSyntaxError("';' expected after 'for'.");
1988         }
1989       }
1990       if (token == TT_ARGCLOSE) {
1991         getNextToken();
1992       } else {
1993         expressionList();
1994         if (token == TT_ARGCLOSE) {
1995           getNextToken();
1996         } else {
1997           throwSyntaxError("')' expected after 'for'.");
1998         }
1999       }
2000       forStatement();
2001       return;
2002     } else if (token == TT_while) {
2003       getNextToken();
2004       if (token == TT_ARGOPEN) {
2005         getNextToken();
2006       } else {
2007         throwSyntaxError("'(' expected after 'while' keyword.");
2008       }
2009       expression();
2010       if (token == TT_ARGCLOSE) {
2011         getNextToken();
2012       } else {
2013         throwSyntaxError("')' expected after 'while' condition.");
2014       }
2015       whileStatement();
2016       return;
2017     } else if (token == TT_do) {
2018       getNextToken();
2019       if (token == TT_LISTOPEN) {
2020         getNextToken();
2021       } else {
2022         throwSyntaxError("'{' expected after 'do' keyword.");
2023       }
2024       if (token != TT_LISTCLOSE) {
2025         statementList();
2026       }
2027       if (token == TT_LISTCLOSE) {
2028         getNextToken();
2029       } else {
2030         throwSyntaxError("'}' expected after 'do' keyword.");
2031       }
2032       if (token == TT_while) {
2033         getNextToken();
2034         if (token == TT_ARGOPEN) {
2035           getNextToken();
2036         } else {
2037           throwSyntaxError("'(' expected after 'while' keyword.");
2038         }
2039         expression();
2040         if (token == TT_ARGCLOSE) {
2041           getNextToken();
2042         } else {
2043           throwSyntaxError("')' expected after 'while' condition.");
2044         }
2045       } else {
2046         throwSyntaxError("'while' expected after 'do' keyword.");
2047       }
2048       if (token == TT_SEMICOLON) {
2049         getNextToken();
2050       } else {
2051         if (!phpEnd) {
2052           throwSyntaxError("';' expected after do-while statement.");
2053         }
2054         getNextToken();
2055       }
2056       return;
2057     } else if (token == TT_foreach) {
2058       getNextToken();
2059       if (token == TT_ARGOPEN) {
2060         getNextToken();
2061       } else {
2062         throwSyntaxError("'(' expected after 'foreach' keyword.");
2063       }
2064       expression();
2065       if (token == TT_as) {
2066         getNextToken();
2067       } else {
2068         throwSyntaxError("'as' expected after 'foreach' exxpression.");
2069       }
2070       variable();
2071       if (token == TT_FOREACH) {
2072         getNextToken();
2073         variable();
2074       }
2075       if (token == TT_ARGCLOSE) {
2076         getNextToken();
2077       } else {
2078         throwSyntaxError("')' expected after 'foreach' expression.");
2079       }
2080       foreachStatement();
2081       return;
2082
2083     } else if (token == TT_continue || token == TT_break || token == TT_return) {
2084       getNextToken();
2085       if (token != TT_SEMICOLON) {
2086         expression();
2087       }
2088       if (token == TT_SEMICOLON) {
2089         getNextToken();
2090       } else {
2091         if (!phpEnd) {
2092           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2093         }
2094         getNextToken();
2095       }
2096       return;
2097
2098     } else if (token == TT_echo) {
2099       getNextToken();
2100       expressionList();
2101       if (token == TT_SEMICOLON) {
2102         getNextToken();
2103       } else {
2104         if (!phpEnd) {
2105           throwSyntaxError("';' expected after 'echo' statement.");
2106         }
2107         getNextToken();
2108       }
2109       return;
2110       //    } else if (token == TT_print) {
2111       //      getNextToken();
2112       //      expression();
2113       //      if (token == TT_SEMICOLON) {
2114       //        getNextToken();
2115       //      } else {
2116       //        if (!phpEnd) {
2117       //          throwSyntaxError("';' expected after 'print' statement.");
2118       //        }
2119       //        getNextToken();
2120       //      }
2121       //      return;
2122
2123     } else if (token == TT_global || token == TT_static) {
2124       getNextToken();
2125       variableList();
2126       if (token == TT_SEMICOLON) {
2127         getNextToken();
2128       } else {
2129         if (!phpEnd) {
2130           throwSyntaxError("';' expected after 'global' or 'static' statement.");
2131         }
2132         getNextToken();
2133       }
2134       return;
2135
2136       //      } else if (token == TT_unset) {
2137       //        getNextToken();
2138       //        if (token == TT_ARGOPEN) {
2139       //          getNextToken();
2140       //        } else {
2141       //          throwSyntaxError("'(' expected after 'unset' keyword.");
2142       //        }
2143       //        variableList();
2144       //        if (token == TT_ARGCLOSE) {
2145       //          getNextToken();
2146       //        } else {
2147       //          throwSyntaxError("')' expected after 'unset' statement.");
2148       //        }
2149       //        if (token == TT_SEMICOLON) {
2150       //          getNextToken();
2151       //        } else {
2152       //          if (!phpEnd) {
2153       //            throwSyntaxError("';' expected after 'unset' statement.");
2154       //          }
2155       //          getNextToken();
2156       //        }
2157       //        return;
2158
2159       //      } else if (token == TT_exit || token == TT_die) {
2160       //        getNextToken();
2161       //        if (token != TT_SEMICOLON) {
2162       //          exitStatus();
2163       //        }
2164       //        if (token == TT_SEMICOLON) {
2165       //          getNextToken();
2166       //        } else {
2167       //          if (!phpEnd) {
2168       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2169       //          }
2170       //          getNextToken();
2171       //        }
2172       //        return;
2173
2174     } else if (token == TT_define) {
2175       getNextToken();
2176       if (token == TT_ARGOPEN) {
2177         getNextToken();
2178       } else {
2179         throwSyntaxError("'(' expected after 'define' keyword.");
2180       }
2181       expression();
2182       if (token == TT_COMMA) {
2183         getNextToken();
2184       } else {
2185         throwSyntaxError("',' expected after first 'define' constant.");
2186       }
2187       expression();
2188       if (token == TT_COMMA) {
2189         getNextToken();
2190         expression();
2191       }
2192       if (token == TT_ARGCLOSE) {
2193         getNextToken();
2194       } else {
2195         throwSyntaxError("')' expected after 'define' statement.");
2196       }
2197       if (token == TT_SEMICOLON) {
2198         getNextToken();
2199       } else {
2200         if (!phpEnd) {
2201           throwSyntaxError("';' expected after 'define' statement.");
2202         }
2203         getNextToken();
2204       }
2205       return;
2206     } else if (token == TT_function) {
2207       getNextToken();
2208       functionDefinition();
2209       return;
2210     } else if (token == TT_class) {
2211       getNextToken();
2212       classDeclarator();
2213       classBody();
2214       return;
2215       //      } else {
2216       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
2217     } else if (token == TT_LISTOPEN) {
2218       // compoundStatement
2219       getNextToken();
2220       if (token != TT_LISTCLOSE) {
2221         statementList();
2222       }
2223       if (token == TT_LISTCLOSE) {
2224         getNextToken();
2225         return;
2226       } else {
2227         throwSyntaxError("'}' expected.");
2228       }
2229     } else {
2230       if (token != TT_SEMICOLON) {
2231         expression();
2232       }
2233       if (token == TT_SEMICOLON) {
2234         getNextToken();
2235         return;
2236       } else {
2237         if (!phpEnd) {
2238           throwSyntaxError("';' expected after expression.");
2239         }
2240         getNextToken();
2241       }
2242     }
2243   }
2244
2245   private void classDeclarator() throws CoreException {
2246     //identifier
2247     //identifier 'extends' identifier
2248     if (token == TT_IDENTIFIER) {
2249       getNextToken();
2250       if (token == TT_extends) {
2251         getNextToken();
2252         if (token == TT_IDENTIFIER) {
2253           getNextToken();
2254         } else {
2255           throwSyntaxError("Class name expected after keyword 'extends'.");
2256         }
2257       }
2258     } else {
2259       throwSyntaxError("Class name expected after keyword 'class'.");
2260     }
2261   }
2262
2263   private void classBody() throws CoreException {
2264     //'{' [class-element-list] '}'
2265     if (token == TT_LISTOPEN) {
2266       getNextToken();
2267       if (token != TT_LISTCLOSE) {
2268         classElementList();
2269       }
2270       if (token == TT_LISTCLOSE) {
2271         getNextToken();
2272       } else {
2273         throwSyntaxError("'}' expected at end of class body.");
2274       }
2275     } else {
2276       throwSyntaxError("'{' expected at start of class body.");
2277     }
2278   }
2279
2280   private void classElementList() throws CoreException {
2281     do {
2282       classElement();
2283     } while (token == TT_function || token == TT_var);
2284   }
2285
2286   private void classElement() throws CoreException {
2287     //class-property
2288     //function-definition
2289     if (token == TT_function) {
2290       getNextToken();
2291       functionDefinition();
2292     } else if (token == TT_var) {
2293       getNextToken();
2294       classProperty();
2295     } else {
2296       throwSyntaxError("'function' or 'var' expected.");
2297     }
2298   }
2299
2300   private void classProperty() throws CoreException {
2301     //'var' variable ';'
2302     //'var' variable '=' constant ';'
2303     do {
2304       if (token == TT_VARIABLE) {
2305         getNextToken();
2306         if (token == TT_ASSIGN) {
2307           getNextToken();
2308           constant();
2309         }
2310       } else {
2311         throwSyntaxError("Variable expected after keyword 'var'.");
2312       }
2313       if (token != TT_COMMA) {
2314         break;
2315       }
2316       getNextToken();
2317     } while (true);
2318     if (token == TT_SEMICOLON) {
2319       getNextToken();
2320     } else {
2321       throwSyntaxError("';' expected after variable declaration.");
2322     }
2323   }
2324
2325   private void functionDefinition() throws CoreException {
2326     functionDeclarator();
2327     compoundStatement();
2328   }
2329
2330   private void functionDeclarator() throws CoreException {
2331     //identifier '(' [parameter-list] ')'
2332     if (token == TT_AMPERSAND) {
2333       getNextToken();
2334     }
2335     if (token == TT_IDENTIFIER) {
2336       getNextToken();
2337       if (token == TT_ARGOPEN) {
2338         getNextToken();
2339       } else {
2340         throwSyntaxError("'(' expected in function declaration.");
2341       }
2342       if (token != TT_ARGCLOSE) {
2343         parameterList();
2344       }
2345       if (token != TT_ARGCLOSE) {
2346         throwSyntaxError("')' expected in function declaration.");
2347       } else {
2348         getNextToken();
2349       }
2350     }
2351   }
2352   //
2353   private void parameterList() throws CoreException {
2354     //parameter-declaration
2355     //parameter-list ',' parameter-declaration
2356     do {
2357       parameterDeclaration();
2358       if (token != TT_COMMA) {
2359         break;
2360       }
2361       getNextToken();
2362     } while (true);
2363   }
2364
2365   private void parameterDeclaration() throws CoreException {
2366     //variable
2367     //variable-reference
2368     if (token == TT_AMPERSAND) {
2369       getNextToken();
2370       if (token == TT_VARIABLE) {
2371         getNextToken();
2372       } else {
2373         throwSyntaxError("Variable expected after reference operator '&'.");
2374       }
2375     }
2376     //variable '=' constant
2377     if (token == TT_VARIABLE) {
2378       getNextToken();
2379       if (token == TT_ASSIGN) {
2380         getNextToken();
2381         constant();
2382       }
2383       return;
2384     }
2385   }
2386
2387   private void labeledStatementList() throws CoreException {
2388     if (token != TT_case && token != TT_default) {
2389       throwSyntaxError("'case' or 'default' expected.");
2390     }
2391     do {
2392       if (token == TT_case) {
2393         getNextToken();
2394         constant();
2395         if (token == TT_DDOT) {
2396           getNextToken();
2397           if (token == TT_case || token == TT_default) { // empty case statement ?
2398             continue;
2399           }
2400           statementList();
2401         } else if (token == TT_SEMICOLON) {
2402           setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2403           getNextToken();
2404           if (token == TT_case) { // empty case statement ?
2405             continue;
2406           }
2407           statementList();
2408         } else {
2409           throwSyntaxError("':' character after 'case' constant expected.");
2410         }
2411       } else { // TT_default
2412         getNextToken();
2413         if (token == TT_DDOT) {
2414           getNextToken();
2415           statementList();
2416         } else {
2417           throwSyntaxError("':' character after 'default' expected.");
2418         }
2419       }
2420     } while (token == TT_case || token == TT_default);
2421   }
2422
2423   //  public void labeledStatement() {
2424   //    if (token == TT_case) {
2425   //      getNextToken();
2426   //      constant();
2427   //      if (token == TT_DDOT) {
2428   //        getNextToken();
2429   //        statement();
2430   //      } else {
2431   //        throwSyntaxError("':' character after 'case' constant expected.");
2432   //      }
2433   //      return;
2434   //    } else if (token == TT_default) {
2435   //      getNextToken();
2436   //      if (token == TT_DDOT) {
2437   //        getNextToken();
2438   //        statement();
2439   //      } else {
2440   //        throwSyntaxError("':' character after 'default' expected.");
2441   //      }
2442   //      return;
2443   //    }
2444   //  }
2445
2446   //  public void expressionStatement() {
2447   //  }
2448
2449   //  private void inclusionStatement() {
2450   //  }
2451
2452   //  public void compoundStatement() {
2453   //  }
2454
2455   //  public void selectionStatement() {
2456   //  }
2457   //
2458   //  public void iterationStatement() {
2459   //  }
2460   //
2461   //  public void jumpStatement() {
2462   //  }
2463   //
2464   //  public void outputStatement() {
2465   //  }
2466   //
2467   //  public void scopeStatement() {
2468   //  }
2469   //
2470   //  public void flowStatement() {
2471   //  }
2472   //
2473   //  public void definitionStatement() {
2474   //  }
2475
2476   private void ifStatement() throws CoreException {
2477     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2478     if (token == TT_DDOT) {
2479       getNextToken();
2480       statementList();
2481       switch (token) {
2482         case TT_else :
2483           getNextToken();
2484           if (token == TT_DDOT) {
2485             getNextToken();
2486             statementList();
2487           } else {
2488             if (token == TT_if) { //'else if'
2489               getNextToken();
2490               elseifStatementList();
2491             } else {
2492               throwSyntaxError("':' expected after 'else'.");
2493             }
2494           }
2495           break;
2496         case TT_elseif :
2497           getNextToken();
2498           elseifStatementList();
2499           break;
2500       }
2501
2502       if (token != TT_endif) {
2503         throwSyntaxError("'endif' expected.");
2504       }
2505       getNextToken();
2506       if (token != TT_SEMICOLON) {
2507         throwSyntaxError("';' expected after if-statement.");
2508       }
2509       getNextToken();
2510     } else {
2511       // statement [else-statement]
2512       statement();
2513       if (token == TT_elseif) {
2514         getNextToken();
2515         if (token == TT_ARGOPEN) {
2516           getNextToken();
2517         } else {
2518           throwSyntaxError("'(' expected after 'elseif' keyword.");
2519         }
2520         expression();
2521         if (token == TT_ARGCLOSE) {
2522           getNextToken();
2523         } else {
2524           throwSyntaxError("')' expected after 'elseif' condition.");
2525         }
2526         ifStatement();
2527       } else if (token == TT_else) {
2528         getNextToken();
2529         statement();
2530       }
2531     }
2532   }
2533
2534   private void elseifStatementList() throws CoreException {
2535     do {
2536       elseifStatement();
2537       switch (token) {
2538         case TT_else :
2539           getNextToken();
2540           if (token == TT_DDOT) {
2541             getNextToken();
2542             statementList();
2543             return;
2544           } else {
2545             if (token == TT_if) { //'else if'
2546               getNextToken();
2547             } else {
2548               throwSyntaxError("':' expected after 'else'.");
2549             }
2550           }
2551           break;
2552         case TT_elseif :
2553           getNextToken();
2554           break;
2555         default :
2556           return;
2557       }
2558     } while (true);
2559   }
2560
2561   private void elseifStatement() throws CoreException {
2562     if (token == TT_ARGOPEN) {
2563       getNextToken();
2564       expression();
2565       if (token != TT_ARGOPEN) {
2566         throwSyntaxError("')' expected in else-if-statement.");
2567       }
2568       getNextToken();
2569       if (token != TT_DDOT) {
2570         throwSyntaxError("':' expected in else-if-statement.");
2571       }
2572       getNextToken();
2573       statementList();
2574     }
2575   }
2576
2577   private void switchStatement() throws CoreException {
2578     if (token == TT_DDOT) {
2579       // ':' [labeled-statement-list] 'endswitch' ';'
2580       getNextToken();
2581       labeledStatementList();
2582       if (token != TT_endswitch) {
2583         throwSyntaxError("'endswitch' expected.");
2584       }
2585       getNextToken();
2586       if (token != TT_SEMICOLON) {
2587         throwSyntaxError("';' expected after switch-statement.");
2588       }
2589       getNextToken();
2590     } else {
2591       // '{' [labeled-statement-list] '}'
2592       if (token != TT_LISTOPEN) {
2593         throwSyntaxError("'{' expected in switch statement.");
2594       }
2595       getNextToken();
2596       if (token != TT_LISTCLOSE) {
2597         labeledStatementList();
2598       }
2599       if (token != TT_LISTCLOSE) {
2600         throwSyntaxError("'}' expected in switch statement.");
2601       }
2602       getNextToken();
2603
2604     }
2605   }
2606
2607   private void forStatement() throws CoreException {
2608     if (token == TT_DDOT) {
2609       getNextToken();
2610       statementList();
2611       if (token != TT_endfor) {
2612         throwSyntaxError("'endfor' expected.");
2613       }
2614       getNextToken();
2615       if (token != TT_SEMICOLON) {
2616         throwSyntaxError("';' expected after for-statement.");
2617       }
2618       getNextToken();
2619     } else {
2620       statement();
2621     }
2622   }
2623
2624   private void whileStatement() throws CoreException {
2625     // ':' statement-list 'endwhile' ';'
2626     if (token == TT_DDOT) {
2627       getNextToken();
2628       statementList();
2629       if (token != TT_endwhile) {
2630         throwSyntaxError("'endwhile' expected.");
2631       }
2632       getNextToken();
2633       if (token != TT_SEMICOLON) {
2634         throwSyntaxError("';' expected after while-statement.");
2635       }
2636       getNextToken();
2637     } else {
2638       statement();
2639     }
2640   }
2641
2642   private void foreachStatement() throws CoreException {
2643     if (token == TT_DDOT) {
2644       getNextToken();
2645       statementList();
2646       if (token != TT_endforeach) {
2647         throwSyntaxError("'endforeach' expected.");
2648       }
2649       getNextToken();
2650       if (token != TT_SEMICOLON) {
2651         throwSyntaxError("';' expected after foreach-statement.");
2652       }
2653       getNextToken();
2654     } else {
2655       statement();
2656     }
2657   }
2658
2659   private void exitStatus() throws CoreException {
2660     if (token == TT_ARGOPEN) {
2661       getNextToken();
2662     } else {
2663       throwSyntaxError("'(' expected in 'exit-status'.");
2664     }
2665     if (token != TT_ARGCLOSE) {
2666       expression();
2667     }
2668     if (token == TT_ARGCLOSE) {
2669       getNextToken();
2670     } else {
2671       throwSyntaxError("')' expected after 'exit-status'.");
2672     }
2673   }
2674
2675   private void expressionList() throws CoreException {
2676     do {
2677       expression();
2678       if (token == TT_COMMA) {
2679         getNextToken();
2680       } else {
2681         break;
2682       }
2683     } while (true);
2684   }
2685
2686   private void expression() throws CoreException {
2687     //todo: find a better way to get the expression
2688     expression = new StringBuffer();
2689     for (int i = chIndx;i<str.length();i++) {
2690       if (str.charAt(i) == ';') {
2691         break;
2692       }
2693       expression.append(str.charAt(i));
2694     }
2695     //    if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2696     //      getNextToken();
2697     //    } else {
2698     logicalinclusiveorExpression();
2699     //      while (token != TT_SEMICOLON) {
2700     //        getNextToken();
2701     //      //      }
2702     //    }
2703   }
2704
2705   private void postfixExpression() throws CoreException {
2706     String ident;
2707     boolean castFlag = false;
2708     switch (token) {
2709       case TT_new :
2710         getNextToken();
2711         expression();
2712         break;
2713       case TT_null :
2714         getNextToken();
2715         break;
2716       case TT_false :
2717         getNextToken();
2718         break;
2719       case TT_true :
2720         getNextToken();
2721         break;
2722       case TT_STRING_CONSTANT :
2723         getNextToken();
2724         break;
2725       case TT_INTERPOLATED_STRING :
2726         getNextToken();
2727         break;
2728       case TT_ARGOPEN :
2729         getNextToken();
2730         if (token == TT_IDENTIFIER) {
2731           // check if identifier is a type:
2732           ident = identifier;
2733           String str = identifier.toLowerCase();
2734           for (int i = 0; i < PHP_TYPES.length; i++) {
2735             if (PHP_TYPES[i].equals(str)) {
2736               castFlag = true;
2737               break;
2738             }
2739           }
2740           if (castFlag) {
2741             getNextToken();
2742             if (token != TT_ARGCLOSE) {
2743               throwSyntaxError(") expected after cast-type '" + ident + "'.");
2744             }
2745             getNextToken();
2746             expression();
2747             break;
2748           }
2749         }
2750         if (!castFlag) {
2751           expression();
2752         }
2753         if (token != TT_ARGCLOSE) {
2754           throwSyntaxError(") expected in postfix-expression.");
2755         }
2756         getNextToken();
2757         break;
2758       case TT_DOUBLE_NUMBER :
2759         getNextToken();
2760         break;
2761       case TT_INT_NUMBER :
2762         getNextToken();
2763         break;
2764       case TT_DOLLAROPEN :
2765         getNextToken();
2766         expression();
2767         if (token != TT_LISTCLOSE) {
2768           throwSyntaxError("'}' expected after indirect variable token '${'.");
2769         }
2770         getNextToken();
2771         break;
2772       case TT_VARIABLE :
2773         ident = identifier;
2774         getNextToken();
2775         if (token == TT_LISTOPEN) {
2776           getNextToken();
2777           expression();
2778           if (token != TT_LISTCLOSE) {
2779             throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2780           }
2781           getNextToken();
2782         } else if (token == TT_ARGOPEN) {
2783           getNextToken();
2784           if (token != TT_ARGCLOSE) {
2785             expressionList();
2786             if (token != TT_ARGCLOSE) {
2787               throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2788             }
2789           }
2790           getNextToken();
2791         }
2792         break;
2793       case TT_IDENTIFIER :
2794         ident = identifier;
2795         getNextToken();
2796         if (token == TT_ARGOPEN) {
2797           getNextToken();
2798           if (token != TT_ARGCLOSE) {
2799             expressionList();
2800             if (token != TT_ARGCLOSE) {
2801               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2802             }
2803           }
2804           getNextToken();
2805         }
2806         break;
2807       case TT_print :
2808         getNextToken();
2809         expression();
2810         //        if (token == TT_SEMICOLON) {
2811         //          getNextToken();
2812         //        } else {
2813         //          if (!phpEnd) {
2814         //            throwSyntaxError("';' expected after 'print' statement.");
2815         //          }
2816         //          getNextToken();
2817         //        }
2818         break;
2819       case TT_list :
2820         getNextToken();
2821         if (token == TT_ARGOPEN) {
2822           getNextToken();
2823           if (token == TT_COMMA) {
2824             getNextToken();
2825           }
2826           expressionList();
2827           if (token != TT_ARGCLOSE) {
2828             throwSyntaxError("')' expected after 'list' keyword.");
2829           }
2830           getNextToken();
2831           //          if (token == TT_SET) {
2832           //            getNextToken();
2833           //            logicalinclusiveorExpression();
2834           //          }
2835         } else {
2836           throwSyntaxError("'(' expected after 'list' keyword.");
2837         }
2838         break;
2839         //      case TT_exit :
2840         //        getNextToken();
2841         //        if (token != TT_SEMICOLON) {
2842         //          exitStatus();
2843         //        }
2844         //        if (token == TT_SEMICOLON) {
2845         //          getNextToken();
2846         //        } else {
2847         //          if (!phpEnd) {
2848         //            throwSyntaxError("';' expected after 'exit' expression.");
2849         //          }
2850         //          getNextToken();
2851         //        }
2852         //        break;
2853         //      case TT_die :
2854         //        getNextToken();
2855         //        if (token != TT_SEMICOLON) {
2856         //          exitStatus();
2857         //        }
2858         //        if (token == TT_SEMICOLON) {
2859         //          getNextToken();
2860         //        } else {
2861         //          if (!phpEnd) {
2862         //            throwSyntaxError("';' expected after 'die' expression.");
2863         //          }
2864         //        }
2865         //        break;
2866
2867         //      case TT_array :
2868         //        getNextToken();
2869         //        if (token == TT_ARGOPEN) {
2870         //          getNextToken();
2871         //          if (token == TT_COMMA) {
2872         //            getNextToken();
2873         //          }
2874         //          expressionList();
2875         //          if (token != TT_ARGCLOSE) {
2876         //            throwSyntaxError("')' expected after 'list' keyword.");
2877         //          }
2878         //          getNextToken();
2879         //          if (token == TT_SET) {
2880         //            getNextToken();
2881         //            logicalinclusiveorExpression();
2882         //          }
2883         //        } else {
2884         //          throwSyntaxError("'(' expected after 'list' keyword.");
2885         //        }
2886         //        break;
2887     }
2888     boolean while_flag = true;
2889     do {
2890       switch (token) {
2891         case TT_PARTOPEN :
2892           getNextToken();
2893           expression();
2894           if (token != TT_PARTCLOSE) {
2895             throwSyntaxError("] expected in postfix-expression.");
2896           }
2897           getNextToken();
2898           break;
2899         case TT_DDOT2 : // ::
2900         case TT_REF : // ->
2901           getNextToken();
2902           if (token > TT_KEYWORD) {
2903             ident = identifier;
2904             setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2905           }
2906           switch (token) {
2907             case TT_VARIABLE :
2908               ident = identifier;
2909               getNextToken();
2910               //              if (token == TT_ARGOPEN) {
2911               //                getNextToken();
2912               //                expressionList();
2913               //                if (token != TT_ARGCLOSE) {
2914               //                  throwSyntaxError(") expected after variable '" + ident + "'.");
2915               //                }
2916               //                getNextToken();
2917               //              }
2918               break;
2919             case TT_IDENTIFIER :
2920               ident = identifier;
2921               getNextToken();
2922               break;
2923             case TT_LISTOPEN :
2924               getNextToken();
2925               expression();
2926               if (token != TT_LISTCLOSE) {
2927                 throwSyntaxError("} expected in postfix-expression.");
2928               }
2929               getNextToken();
2930               break;
2931             default :
2932               throwSyntaxError("Syntax error after '->' token.");
2933           } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2934               if (token == TT_PARTOPEN) {
2935                 getNextToken();
2936                 expressionList();
2937                 if (token != TT_PARTCLOSE) {
2938                   throwSyntaxError("] expected after '->'.");
2939                 }
2940                 getNextToken();
2941               }
2942               if (token == TT_ARGOPEN) {
2943                 getNextToken();
2944                 expressionList();
2945                 if (token != TT_ARGCLOSE) {
2946                   throwSyntaxError(") expected after '->'.");
2947                 }
2948                 getNextToken();
2949               }
2950               if (token == TT_LISTOPEN) {
2951                 getNextToken();
2952                 expression();
2953                 if (token != TT_LISTCLOSE) {
2954                   throwSyntaxError("} expected after '->'.");
2955                 }
2956                 getNextToken();
2957               }
2958             }
2959           break;
2960         case TT_INCREMENT :
2961           getNextToken();
2962           break;
2963         case TT_DECREMENT :
2964           getNextToken();
2965           break;
2966         default :
2967           while_flag = false;
2968       }
2969
2970     }
2971     while (while_flag);
2972   }
2973
2974   private void unaryExpression() throws CoreException {
2975     switch (token) {
2976       case TT_INCREMENT :
2977         getNextToken();
2978         unaryExpression();
2979         break;
2980       case TT_DECREMENT :
2981         getNextToken();
2982         unaryExpression();
2983         break;
2984         // '@' '&' '*' '+' '-' '~' '!'
2985       case TT_AT :
2986         getNextToken();
2987         castExpression();
2988         break;
2989       case TT_AMPERSAND :
2990         getNextToken();
2991         castExpression();
2992         break;
2993       case TT_MULTIPLY :
2994         getNextToken();
2995         castExpression();
2996         break;
2997       case TT_ADD :
2998         getNextToken();
2999         castExpression();
3000         break;
3001       case TT_SUBTRACT :
3002         getNextToken();
3003         castExpression();
3004         break;
3005       case TT_TILDE :
3006         getNextToken();
3007         castExpression();
3008         break;
3009       case TT_NOT :
3010         getNextToken();
3011         castExpression();
3012         break;
3013       default :
3014         postfixExpression();
3015     }
3016   }
3017
3018   private void castExpression() throws CoreException {
3019     //    if (token == TT_ARGOPEN) {
3020     //      getNextToken();
3021     //      typeName();
3022     //      if (token != TT_ARGCLOSE) {
3023     //        throwSyntaxError(") expected after cast-expression.");
3024     //      }
3025     //      getNextToken();
3026     //    }
3027     unaryExpression();
3028   }
3029
3030   private void typeName() throws CoreException {
3031     //'string' 'unset' 'array' 'object'
3032     //'bool' 'boolean'
3033     //'real' 'double' 'float'
3034     //'int' 'integer'
3035     String ident = "";
3036     if (token == TT_IDENTIFIER) {
3037       ident = identifier;
3038       String str = identifier.toLowerCase();
3039       getNextToken();
3040       for (int i = 0; i < PHP_TYPES.length; i++) {
3041         if (PHP_TYPES[i].equals(str)) {
3042           return;
3043         }
3044       }
3045     }
3046     throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3047   }
3048
3049   private void assignExpression() throws CoreException {
3050     castExpression();
3051     if (token == TT_ASSIGN) { // =
3052       getNextToken();
3053       logicalinclusiveorExpression();
3054     } else if (token == TT_DOTASSIGN) { // .=
3055       getNextToken();
3056       logicalinclusiveorExpression();
3057     } else if (token == TT_FOREACH) { // =>
3058       getNextToken();
3059       logicalinclusiveorExpression();
3060     } else if (token == TT_ADDTO) { // +=
3061       getNextToken();
3062       logicalinclusiveorExpression();
3063     } else if (token == TT_SUBTRACTFROM) { // -=
3064       getNextToken();
3065       logicalinclusiveorExpression();
3066     } else if (token == TT_TIMESBY) { // *=
3067       getNextToken();
3068       logicalinclusiveorExpression();
3069     } else if (token == TT_DIVIDEBY) { // *=
3070       getNextToken();
3071       logicalinclusiveorExpression();
3072     } else if (token == TT_MODASSIGN) { // %=
3073       getNextToken();
3074       logicalinclusiveorExpression();
3075     } else if (token == TT_ANDASSIGN) { // &=
3076       getNextToken();
3077       logicalinclusiveorExpression();
3078     } else if (token == TT_POWASSIGN) { // ^=
3079       getNextToken();
3080       logicalinclusiveorExpression();
3081     } else if (token == TT_LSHIFTASSIGN) { // <<=
3082       getNextToken();
3083       logicalinclusiveorExpression();
3084     } else if (token == TT_RSHIFTASSIGN) { // >>=
3085       getNextToken();
3086       logicalinclusiveorExpression();
3087     } else if (token == TT_TILDEASSIGN) { // ~=
3088       getNextToken();
3089       logicalinclusiveorExpression();
3090     }
3091   }
3092
3093   private void multiplicativeExpression() throws CoreException {
3094     do {
3095       assignExpression();
3096       if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3097         return;
3098       }
3099       getNextToken();
3100     } while (true);
3101   }
3102
3103   private void concatenationExpression() throws CoreException {
3104     do {
3105       multiplicativeExpression();
3106       if (token != TT_DOT) {
3107         return;
3108       }
3109       getNextToken();
3110     } while (true);
3111   }
3112
3113   private void additiveExpression() throws CoreException {
3114     do {
3115       concatenationExpression();
3116       if (token != TT_ADD && token != TT_SUBTRACT) {
3117         return;
3118       }
3119       getNextToken();
3120     } while (true);
3121   }
3122
3123   private void shiftExpression() throws CoreException {
3124     do {
3125       additiveExpression();
3126       if (token != TT_LSHIFT && token != TT_RSHIFT) {
3127         return;
3128       }
3129       getNextToken();
3130     } while (true);
3131   }
3132
3133   private void relationalExpression() throws CoreException {
3134     do {
3135       shiftExpression();
3136       if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3137         return;
3138       }
3139       getNextToken();
3140     } while (true);
3141   }
3142
3143   private void identicalExpression() throws CoreException {
3144     do {
3145       relationalExpression();
3146       if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3147         return;
3148       }
3149       getNextToken();
3150     } while (true);
3151   }
3152
3153   private void equalityExpression() throws CoreException {
3154     do {
3155       identicalExpression();
3156       if (token != TT_EQUAL && token != TT_UNEQUAL) {
3157         return;
3158       }
3159       getNextToken();
3160     } while (true);
3161   }
3162
3163   private void ternaryExpression() throws CoreException {
3164     equalityExpression();
3165     if (token == TT_QUESTIONMARK) {
3166       getNextToken();
3167       expression();
3168       if (token == TT_DDOT) {
3169         getNextToken();
3170         expression();
3171       } else {
3172         throwSyntaxError("':' expected in ternary operator '? :'.");
3173       }
3174     }
3175   }
3176
3177   private void andExpression() throws CoreException {
3178     do {
3179       ternaryExpression();
3180       if (token != TT_AMPERSAND) {
3181         return;
3182       }
3183       getNextToken();
3184     } while (true);
3185   }
3186
3187   private void exclusiveorExpression() throws CoreException {
3188     do {
3189       andExpression();
3190       if (token != TT_POW) {
3191         return;
3192       }
3193       getNextToken();
3194     } while (true);
3195   }
3196
3197   private void inclusiveorExpression() throws CoreException {
3198     do {
3199       exclusiveorExpression();
3200       if (token != TT_LINE) {
3201         return;
3202       }
3203       getNextToken();
3204     } while (true);
3205   }
3206
3207   private void booleanandExpression() throws CoreException {
3208     do {
3209       inclusiveorExpression();
3210       if (token != TT_AND) {
3211         return;
3212       }
3213       getNextToken();
3214     } while (true);
3215   }
3216
3217   private void booleanorExpression() throws CoreException {
3218     do {
3219       booleanandExpression();
3220       if (token != TT_OR) {
3221         return;
3222       }
3223       getNextToken();
3224     } while (true);
3225   }
3226
3227   private void logicalandExpression() throws CoreException {
3228     do {
3229       booleanorExpression();
3230       if (token != TT_and) {
3231         return;
3232       }
3233       getNextToken();
3234     } while (true);
3235   }
3236
3237   private void logicalexclusiveorExpression() throws CoreException {
3238     do {
3239       logicalandExpression();
3240       if (token != TT_xor) {
3241         return;
3242       }
3243       getNextToken();
3244     } while (true);
3245   }
3246
3247   private void logicalinclusiveorExpression() throws CoreException {
3248     do {
3249       logicalexclusiveorExpression();
3250       if (token != TT_or) {
3251         return;
3252       }
3253       getNextToken();
3254     } while (true);
3255   }
3256
3257   //  public void assignmentExpression() {
3258   //    if (token == TT_VARIABLE) {
3259   //      getNextToken();
3260   //      if (token == TT_SET) {
3261   //        getNextToken();
3262   //        logicalinclusiveorExpression();
3263   //      }
3264   //    } else {
3265   //      logicalinclusiveorExpression();
3266   //    }
3267   //  }
3268
3269   private void variableList() throws CoreException {
3270     do {
3271       variable();
3272       if (token == TT_COMMA) {
3273         getNextToken();
3274       } else {
3275         break;
3276       }
3277     } while (true);
3278   }
3279
3280   private void variable() throws CoreException {
3281     if (token == TT_DOLLAROPEN) {
3282       getNextToken();
3283       expression();
3284       ;
3285       if (token != TT_LISTCLOSE) {
3286         throwSyntaxError("'}' expected after indirect variable token '${'.");
3287       }
3288       getNextToken();
3289     } else {
3290       if (token == TT_VARIABLE) {
3291         getNextToken();
3292         if (token == TT_PARTOPEN) {
3293           getNextToken();
3294           expression();
3295           if (token != TT_PARTCLOSE) {
3296             throwSyntaxError("']' expected in variable-list.");
3297           }
3298           getNextToken();
3299         } else if (token == TT_ASSIGN) {
3300           getNextToken();
3301           constant();
3302         }
3303       } else {
3304         throwSyntaxError("$-variable expected in variable-list.");
3305       }
3306     }
3307   }
3308
3309   private void constant() throws CoreException {
3310     String ident;
3311     switch (token) {
3312       case TT_ADD :
3313         getNextToken();
3314         switch (token) {
3315           case TT_DOUBLE_NUMBER :
3316             getNextToken();
3317             break;
3318           case TT_INT_NUMBER :
3319             getNextToken();
3320             break;
3321           default :
3322             throwSyntaxError("Constant expected after '+' presign.");
3323         }
3324         break;
3325       case TT_SUBTRACT :
3326         getNextToken();
3327         switch (token) {
3328           case TT_DOUBLE_NUMBER :
3329             getNextToken();
3330             break;
3331           case TT_INT_NUMBER :
3332             getNextToken();
3333             break;
3334           default :
3335             throwSyntaxError("Constant expected after '-' presign.");
3336         }
3337         break;
3338       case TT_null :
3339         getNextToken();
3340         break;
3341       case TT_false :
3342         getNextToken();
3343         break;
3344       case TT_true :
3345         getNextToken();
3346         break;
3347       case TT_IDENTIFIER :
3348         ident = identifier;
3349         getNextToken();
3350         if (token == TT_ARGOPEN) {
3351           getNextToken();
3352           if (token != TT_ARGCLOSE) {
3353             expressionList();
3354             if (token != TT_ARGCLOSE) {
3355               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3356             }
3357           }
3358           getNextToken();
3359         }
3360         break;
3361       case TT_STRING_CONSTANT :
3362         getNextToken();
3363         break;
3364       case TT_INTERPOLATED_STRING :
3365         getNextToken();
3366         break;
3367       case TT_DOUBLE_NUMBER :
3368         getNextToken();
3369         break;
3370       case TT_INT_NUMBER :
3371         getNextToken();
3372         break;
3373       default :
3374         throwSyntaxError("Constant expected.");
3375     }
3376   }
3377
3378   /**
3379    * Call the php parse command ( php -l -f &lt;filename&gt; )
3380    * and create markers according to the external parser output
3381    */
3382   public static void phpExternalParse(IFile file) {
3383     //IFile file = (IFile) resource;
3384     IPath path = file.getFullPath();
3385     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3386     String filename = file.getLocation().toString();
3387
3388     String[] arguments = { filename };
3389     MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3390     String command = form.format(arguments);
3391
3392     String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3393
3394     try {
3395       // parse the buffer to find the errors and warnings
3396       createMarkers(parserResult, file);
3397     } catch (CoreException e) {
3398     }
3399   }
3400
3401   /**
3402    * Create markers according to the external parser output
3403    */
3404   private static void createMarkers(String output, IFile file) throws CoreException {
3405     // delete all markers
3406     file.deleteMarkers(IMarker.PROBLEM, false, 0);
3407
3408     int indx = 0;
3409     int brIndx = 0;
3410     boolean flag = true;
3411     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3412       // newer php error output (tested with 4.2.3)
3413       scanLine(output, file, indx, brIndx);
3414       indx = brIndx + 6;
3415       flag = false;
3416     }
3417     if (flag) {
3418       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3419         // older php error output (tested with 4.2.3)
3420         scanLine(output, file, indx, brIndx);
3421         indx = brIndx + 4;
3422       }
3423     }
3424   }
3425
3426   private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3427     String current;
3428     String outLineNumberString;
3429     StringBuffer lineNumberBuffer = new StringBuffer(10);
3430     char ch;
3431     current = output.substring(indx, brIndx);
3432
3433     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3434       int onLine = current.indexOf("on line <b>");
3435       if (onLine != -1) {
3436         lineNumberBuffer.delete(0, lineNumberBuffer.length());
3437         for (int i = onLine; i < current.length(); i++) {
3438           ch = current.charAt(i);
3439           if ('0' <= ch && '9' >= ch) {
3440             lineNumberBuffer.append(ch);
3441           }
3442         }
3443
3444         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3445
3446         Hashtable attributes = new Hashtable();
3447
3448         current = current.replaceAll("\n", "");
3449         current = current.replaceAll("<b>", "");
3450         current = current.replaceAll("</b>", "");
3451         MarkerUtilities.setMessage(attributes, current);
3452
3453         if (current.indexOf(PARSE_ERROR_STRING) != -1)
3454           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3455         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3456           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3457         else
3458           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3459         MarkerUtilities.setLineNumber(attributes, lineNumber);
3460         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
3461       }
3462     }
3463   }
3464 }