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