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