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