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