Syntax Highlighting Prefs work now / Automatic parse on save option available
[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     // start up
1030     try {
1031       this.str = s;
1032       if (s == null) {
1033         if (phpList.size() != 0) {
1034           this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1035         }
1036       }
1037       this.token = TT_EOF;
1038       this.chIndx = 0;
1039       this.rowCount = rowCount;
1040       this.columnCount = 0;
1041       this.phpEnd = false;
1042       getNextToken();
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     } catch (SyntaxError err) {
1070       if (s != null) {
1071         throw err;
1072       } else {
1073         setMarker(err.getMessage(), err.getLine(), ERROR);
1074       }
1075     }
1076   }
1077
1078   private void statementList() throws CoreException {
1079     do {
1080       statement();
1081       if ((token == TT_LISTCLOSE)
1082         || (token == TT_case)
1083         || (token == TT_default)
1084         || (token == TT_elseif)
1085         || (token == TT_endif)
1086         || (token == TT_endfor)
1087         || (token == TT_endforeach)
1088         || (token == TT_endwhile)
1089         || (token == TT_endswitch)
1090         || (token == TT_EOF)
1091         || (token == TT_UNDEFINED)) {
1092         return;
1093       }
1094     } while (true);
1095   }
1096
1097   private void compoundStatement() throws CoreException {
1098     // '{' [statement-list] '}'
1099     if (token == TT_LISTOPEN) {
1100       getNextToken();
1101     } else {
1102       throwSyntaxError("'{' expected in compound-statement.");
1103     }
1104     if (token != TT_LISTCLOSE) {
1105       statementList();
1106     }
1107     if (token == TT_LISTCLOSE) {
1108       getNextToken();
1109     } else {
1110       throwSyntaxError("'}' expected in compound-statement.");
1111     }
1112   }
1113
1114   private void statement() throws CoreException {
1115     //   if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1116     String keyword = identifier;
1117     if (token == TT_include || token == TT_include_once) {
1118       getNextToken();
1119       expression();
1120       if (token == TT_SEMICOLON) {
1121         getNextToken();
1122       } else {
1123         if (!phpEnd) {
1124           throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1125         }
1126       }
1127       return;
1128     } else if (token == TT_require || token == TT_require_once) {
1129       getNextToken();
1130       //constant();
1131       expression();
1132       if (token == TT_SEMICOLON) {
1133         getNextToken();
1134       } else {
1135         if (!phpEnd) {
1136           throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1137         }
1138       }
1139       return;
1140     } else if (token == TT_if) {
1141       getNextToken();
1142       if (token == TT_ARGOPEN) {
1143         getNextToken();
1144       } else {
1145         throwSyntaxError("'(' expected after 'if' keyword.");
1146       }
1147       expression();
1148       if (token == TT_ARGCLOSE) {
1149         getNextToken();
1150       } else {
1151         throwSyntaxError("')' expected after 'if' condition.");
1152       }
1153       ifStatement();
1154       return;
1155
1156     } else if (token == TT_switch) {
1157       getNextToken();
1158       if (token == TT_ARGOPEN) {
1159         getNextToken();
1160       } else {
1161         throwSyntaxError("'(' expected after 'switch' keyword.");
1162       }
1163       expression();
1164       if (token == TT_ARGCLOSE) {
1165         getNextToken();
1166       } else {
1167         throwSyntaxError("')' expected after 'switch' condition.");
1168       }
1169       switchStatement();
1170       return;
1171     } else if (token == TT_for) {
1172       getNextToken();
1173       if (token == TT_ARGOPEN) {
1174         getNextToken();
1175       } else {
1176         throwSyntaxError("'(' expected after 'for' keyword.");
1177       }
1178       if (token == TT_SEMICOLON) {
1179         getNextToken();
1180       } else {
1181         expressionList();
1182         if (token == TT_SEMICOLON) {
1183           getNextToken();
1184         } else {
1185           throwSyntaxError("';' expected after 'for'.");
1186         }
1187       }
1188       if (token == TT_SEMICOLON) {
1189         getNextToken();
1190       } else {
1191         expressionList();
1192         if (token == TT_SEMICOLON) {
1193           getNextToken();
1194         } else {
1195           throwSyntaxError("';' expected after 'for'.");
1196         }
1197       }
1198       if (token == TT_ARGCLOSE) {
1199         getNextToken();
1200       } else {
1201         expressionList();
1202         if (token == TT_ARGCLOSE) {
1203           getNextToken();
1204         } else {
1205           throwSyntaxError("')' expected after 'for'.");
1206         }
1207       }
1208       forStatement();
1209       return;
1210     } else if (token == TT_while) {
1211       getNextToken();
1212       if (token == TT_ARGOPEN) {
1213         getNextToken();
1214       } else {
1215         throwSyntaxError("'(' expected after 'while' keyword.");
1216       }
1217       expression();
1218       if (token == TT_ARGCLOSE) {
1219         getNextToken();
1220       } else {
1221         throwSyntaxError("')' expected after 'while' condition.");
1222       }
1223       whileStatement();
1224       return;
1225     } else if (token == TT_do) {
1226       getNextToken();
1227       if (token == TT_LISTOPEN) {
1228         getNextToken();
1229       } else {
1230         throwSyntaxError("'{' expected after 'do' keyword.");
1231       }
1232       if (token != TT_LISTCLOSE) {
1233         statementList();
1234       }
1235       if (token == TT_LISTCLOSE) {
1236         getNextToken();
1237       } else {
1238         throwSyntaxError("'}' expected after 'do' keyword.");
1239       }
1240       if (token == TT_while) {
1241         getNextToken();
1242         if (token == TT_ARGOPEN) {
1243           getNextToken();
1244         } else {
1245           throwSyntaxError("'(' expected after 'while' keyword.");
1246         }
1247         expression();
1248         if (token == TT_ARGCLOSE) {
1249           getNextToken();
1250         } else {
1251           throwSyntaxError("')' expected after 'while' condition.");
1252         }
1253       } else {
1254         throwSyntaxError("'while' expected after 'do' keyword.");
1255       }
1256       if (token == TT_SEMICOLON) {
1257         getNextToken();
1258       } else {
1259         if (!phpEnd) {
1260           throwSyntaxError("';' expected after do-while statement.");
1261         }
1262       }
1263       return;
1264     } else if (token == TT_foreach) {
1265       getNextToken();
1266       if (token == TT_ARGOPEN) {
1267         getNextToken();
1268       } else {
1269         throwSyntaxError("'(' expected after 'foreach' keyword.");
1270       }
1271       expression();
1272       if (token == TT_as) {
1273         getNextToken();
1274       } else {
1275         throwSyntaxError("'as' expected after 'foreach' exxpression.");
1276       }
1277       variable();
1278       if (token == TT_FOREACH) {
1279         getNextToken();
1280         variable();
1281       }
1282       if (token == TT_ARGCLOSE) {
1283         getNextToken();
1284       } else {
1285         throwSyntaxError("')' expected after 'foreach' expression.");
1286       }
1287       foreachStatement();
1288       return;
1289
1290     } else if (token == TT_continue || token == TT_break || token == TT_return) {
1291       getNextToken();
1292       if (token != TT_SEMICOLON) {
1293         expression();
1294       }
1295       if (token == TT_SEMICOLON) {
1296         getNextToken();
1297       } else {
1298         if (!phpEnd) {
1299           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
1300         }
1301       }
1302       return;
1303
1304     } else if (token == TT_echo) {
1305       getNextToken();
1306       expressionList();
1307       if (token == TT_SEMICOLON) {
1308         getNextToken();
1309       } else {
1310         if (!phpEnd) {
1311           throwSyntaxError("';' expected after 'echo' statement.");
1312         }
1313       }
1314       return;
1315       //    } else if (token == TT_print) {
1316       //      getNextToken();
1317       //      expression();
1318       //      if (token == TT_SEMICOLON) {
1319       //        getNextToken();
1320       //      } else {
1321       //        if (!phpEnd) {
1322       //          throwSyntaxError("';' expected after 'print' statement.");
1323       //        }
1324       //      }
1325       //      return;
1326
1327     } else if (token == TT_global || token == TT_static) {
1328       getNextToken();
1329       variableList();
1330       if (token == TT_SEMICOLON) {
1331         getNextToken();
1332       } else {
1333         if (!phpEnd) {
1334           throwSyntaxError("';' expected after 'global' or 'static' statement.");
1335         }
1336       }
1337       return;
1338
1339       //      } else if (token == TT_unset) {
1340       //        getNextToken();
1341       //        if (token == TT_ARGOPEN) {
1342       //          getNextToken();
1343       //        } else {
1344       //          throwSyntaxError("'(' expected after 'unset' keyword.");
1345       //        }
1346       //        variableList();
1347       //        if (token == TT_ARGCLOSE) {
1348       //          getNextToken();
1349       //        } else {
1350       //          throwSyntaxError("')' expected after 'unset' statement.");
1351       //        }
1352       //        if (token == TT_SEMICOLON) {
1353       //          getNextToken();
1354       //        } else {
1355       //          if (!phpEnd) {
1356       //            throwSyntaxError("';' expected after 'unset' statement.");
1357       //          }
1358       //        }
1359       //        return;
1360
1361       //      } else if (token == TT_exit || token == TT_die) {
1362       //        getNextToken();
1363       //        if (token != TT_SEMICOLON) {
1364       //          exitStatus();
1365       //        }
1366       //        if (token == TT_SEMICOLON) {
1367       //          getNextToken();
1368       //        } else {
1369       //          if (!phpEnd) {
1370       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
1371       //          }
1372       //        }
1373       //        return;
1374
1375     } else if (token == TT_define) {
1376       getNextToken();
1377       if (token == TT_ARGOPEN) {
1378         getNextToken();
1379       } else {
1380         throwSyntaxError("'(' expected after 'define' keyword.");
1381       }
1382       expression();
1383       if (token == TT_COMMA) {
1384         getNextToken();
1385       } else {
1386         throwSyntaxError("',' expected after first 'define' constant.");
1387       }
1388       expression();
1389       if (token == TT_COMMA) {
1390         getNextToken();
1391         expression();
1392       }
1393       if (token == TT_ARGCLOSE) {
1394         getNextToken();
1395       } else {
1396         throwSyntaxError("')' expected after 'define' statement.");
1397       }
1398       if (token == TT_SEMICOLON) {
1399         getNextToken();
1400       } else {
1401         if (!phpEnd) {
1402           throwSyntaxError("';' expected after 'define' statement.");
1403         }
1404       }
1405       return;
1406     } else if (token == TT_function) {
1407       getNextToken();
1408       functionDefinition();
1409       return;
1410     } else if (token == TT_class) {
1411       getNextToken();
1412       classDeclarator();
1413       classBody();
1414       return;
1415       //      } else {
1416       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
1417     } else if (token == TT_LISTOPEN) {
1418       // compoundStatement
1419       getNextToken();
1420       if (token != TT_LISTCLOSE) {
1421         statementList();
1422       }
1423       if (token == TT_LISTCLOSE) {
1424         getNextToken();
1425         return;
1426       } else {
1427         throwSyntaxError("'}' expected.");
1428       }
1429     } else {
1430       if (token != TT_SEMICOLON) {
1431         expression();
1432       }
1433       if (token == TT_SEMICOLON) {
1434         getNextToken();
1435         return;
1436       } else {
1437         if (!phpEnd) {
1438           throwSyntaxError("';' expected after expression.");
1439         }
1440       }
1441     }
1442   }
1443
1444   private void classDeclarator() throws CoreException {
1445     //identifier
1446     //identifier 'extends' identifier
1447     if (token == TT_IDENTIFIER) {
1448       getNextToken();
1449       if (token == TT_extends) {
1450         getNextToken();
1451         if (token == TT_IDENTIFIER) {
1452           getNextToken();
1453         } else {
1454           throwSyntaxError("Class name expected after keyword 'extends'.");
1455         }
1456       }
1457     } else {
1458       throwSyntaxError("Class name expected after keyword 'class'.");
1459     }
1460   }
1461
1462   private void classBody() throws CoreException {
1463     //'{' [class-element-list] '}'
1464     if (token == TT_LISTOPEN) {
1465       getNextToken();
1466       if (token != TT_LISTCLOSE) {
1467         classElementList();
1468       }
1469       if (token == TT_LISTCLOSE) {
1470         getNextToken();
1471       } else {
1472         throwSyntaxError("'}' expected at end of class body.");
1473       }
1474     } else {
1475       throwSyntaxError("'{' expected at start of class body.");
1476     }
1477   }
1478
1479   private void classElementList() throws CoreException {
1480     do {
1481       classElement();
1482     } while (token == TT_function || token == TT_var);
1483   }
1484
1485   private void classElement() throws CoreException {
1486     //class-property
1487     //function-definition
1488     if (token == TT_function) {
1489       getNextToken();
1490       functionDefinition();
1491     } else if (token == TT_var) {
1492       getNextToken();
1493       classProperty();
1494     } else {
1495       throwSyntaxError("'function' or 'var' expected.");
1496     }
1497   }
1498
1499   private void classProperty() throws CoreException {
1500     //'var' variable ';'
1501     //'var' variable '=' constant ';'
1502     do {
1503       if (token == TT_VARIABLE) {
1504         getNextToken();
1505         if (token == TT_ASSIGN) {
1506           getNextToken();
1507           constant();
1508         }
1509       } else {
1510         throwSyntaxError("Variable expected after keyword 'var'.");
1511       }
1512       if (token != TT_COMMA) {
1513         break;
1514       }
1515       getNextToken();
1516     } while (true);
1517     if (token == TT_SEMICOLON) {
1518       getNextToken();
1519     } else {
1520       throwSyntaxError("';' expected after variable declaration.");
1521     }
1522   }
1523
1524   private void functionDefinition() throws CoreException {
1525     functionDeclarator();
1526     compoundStatement();
1527   }
1528
1529   private void functionDeclarator() throws CoreException {
1530     //identifier '(' [parameter-list] ')'
1531     if (token == TT_AMPERSAND) {
1532       getNextToken();
1533     }
1534     if (token == TT_IDENTIFIER) {
1535       getNextToken();
1536       if (token == TT_ARGOPEN) {
1537         getNextToken();
1538       } else {
1539         throwSyntaxError("'(' expected in function declaration.");
1540       }
1541       if (token != TT_ARGCLOSE) {
1542         parameterList();
1543       }
1544       if (token != TT_ARGCLOSE) {
1545         throwSyntaxError("')' expected in function declaration.");
1546       } else {
1547         getNextToken();
1548       }
1549     }
1550   }
1551   //
1552   private void parameterList() throws CoreException {
1553     //parameter-declaration
1554     //parameter-list ',' parameter-declaration
1555     do {
1556       parameterDeclaration();
1557       if (token != TT_COMMA) {
1558         break;
1559       }
1560       getNextToken();
1561     } while (true);
1562   }
1563
1564   private void parameterDeclaration() throws CoreException {
1565     //variable
1566     //variable-reference
1567     if (token == TT_AMPERSAND) {
1568       getNextToken();
1569       if (token == TT_VARIABLE) {
1570         getNextToken();
1571       } else {
1572         throwSyntaxError("Variable expected after reference operator '&'.");
1573       }
1574     }
1575     //variable '=' constant
1576     if (token == TT_VARIABLE) {
1577       getNextToken();
1578       if (token == TT_ASSIGN) {
1579         getNextToken();
1580         constant();
1581       }
1582       return;
1583     }
1584   }
1585
1586   private void labeledStatementList() throws CoreException {
1587     if (token != TT_case && token != TT_default) {
1588       throwSyntaxError("'case' or 'default' expected.");
1589     }
1590     do {
1591       if (token == TT_case) {
1592         getNextToken();
1593         constant();
1594         if (token == TT_DDOT) {
1595           getNextToken();
1596           if (token == TT_case || token == TT_default) { // empty case statement ?
1597             continue;
1598           }
1599           statementList();
1600         } else if (token == TT_SEMICOLON) {
1601           setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
1602           getNextToken();
1603           if (token == TT_case) { // empty case statement ?
1604             continue;
1605           }
1606           statementList();
1607         } else {
1608           throwSyntaxError("':' character after 'case' constant expected.");
1609         }
1610       } else { // TT_default 
1611         getNextToken();
1612         if (token == TT_DDOT) {
1613           getNextToken();
1614           statementList();
1615         } else {
1616           throwSyntaxError("':' character after 'default' expected.");
1617         }
1618       }
1619     } while (token == TT_case || token == TT_default);
1620   }
1621
1622   //  public void labeledStatement() {
1623   //    if (token == TT_case) {
1624   //      getNextToken();
1625   //      constant();
1626   //      if (token == TT_DDOT) {
1627   //        getNextToken();
1628   //        statement();
1629   //      } else {
1630   //        throwSyntaxError("':' character after 'case' constant expected.");
1631   //      }
1632   //      return;
1633   //    } else if (token == TT_default) {
1634   //      getNextToken();
1635   //      if (token == TT_DDOT) {
1636   //        getNextToken();
1637   //        statement();
1638   //      } else {
1639   //        throwSyntaxError("':' character after 'default' expected.");
1640   //      }
1641   //      return;
1642   //    }
1643   //  }
1644
1645   //  public void expressionStatement() {
1646   //  }
1647
1648   //  private void inclusionStatement() {
1649   //  }
1650
1651   //  public void compoundStatement() {
1652   //  }
1653
1654   //  public void selectionStatement() {
1655   //  }
1656   //
1657   //  public void iterationStatement() {
1658   //  }
1659   //
1660   //  public void jumpStatement() {
1661   //  }
1662   //
1663   //  public void outputStatement() {
1664   //  }
1665   //
1666   //  public void scopeStatement() {
1667   //  }
1668   //
1669   //  public void flowStatement() {
1670   //  }
1671   //
1672   //  public void definitionStatement() {
1673   //  }
1674
1675   private void ifStatement() throws CoreException {
1676     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
1677     if (token == TT_DDOT) {
1678       getNextToken();
1679       statementList();
1680       switch (token) {
1681         case TT_else :
1682           getNextToken();
1683           if (token == TT_DDOT) {
1684             getNextToken();
1685             statementList();
1686           } else {
1687             if (token == TT_if) { //'else if'
1688               getNextToken();
1689               elseifStatementList();
1690             } else {
1691               throwSyntaxError("':' expected after 'else'.");
1692             }
1693           }
1694           break;
1695         case TT_elseif :
1696           getNextToken();
1697           elseifStatementList();
1698           break;
1699       }
1700
1701       if (token != TT_endif) {
1702         throwSyntaxError("'endif' expected.");
1703       }
1704       getNextToken();
1705       if (token != TT_SEMICOLON) {
1706         throwSyntaxError("';' expected after if-statement.");
1707       }
1708       getNextToken();
1709     } else {
1710       // statement [else-statement]
1711       statement();
1712       if (token == TT_elseif) {
1713         getNextToken();
1714         if (token == TT_ARGOPEN) {
1715           getNextToken();
1716         } else {
1717           throwSyntaxError("'(' expected after 'elseif' keyword.");
1718         }
1719         expression();
1720         if (token == TT_ARGCLOSE) {
1721           getNextToken();
1722         } else {
1723           throwSyntaxError("')' expected after 'elseif' condition.");
1724         }
1725         ifStatement();
1726       } else if (token == TT_else) {
1727         getNextToken();
1728         statement();
1729       }
1730     }
1731   }
1732
1733   private void elseifStatementList() throws CoreException {
1734     do {
1735       elseifStatement();
1736       switch (token) {
1737         case TT_else :
1738           getNextToken();
1739           if (token == TT_DDOT) {
1740             getNextToken();
1741             statementList();
1742             return;
1743           } else {
1744             if (token == TT_if) { //'else if'
1745               getNextToken();
1746             } else {
1747               throwSyntaxError("':' expected after 'else'.");
1748             }
1749           }
1750           break;
1751         case TT_elseif :
1752           getNextToken();
1753           break;
1754         default :
1755           return;
1756       }
1757     } while (true);
1758   }
1759
1760   private void elseifStatement() throws CoreException {
1761     if (token == TT_ARGOPEN) {
1762       getNextToken();
1763       expression();
1764       if (token != TT_ARGOPEN) {
1765         throwSyntaxError("')' expected in else-if-statement.");
1766       }
1767       getNextToken();
1768       if (token != TT_DDOT) {
1769         throwSyntaxError("':' expected in else-if-statement.");
1770       }
1771       getNextToken();
1772       statementList();
1773     }
1774   }
1775
1776   private void switchStatement() throws CoreException {
1777     if (token == TT_DDOT) {
1778       // ':' [labeled-statement-list] 'endswitch' ';'
1779       getNextToken();
1780       labeledStatementList();
1781       if (token != TT_endswitch) {
1782         throwSyntaxError("'endswitch' expected.");
1783       }
1784       getNextToken();
1785       if (token != TT_SEMICOLON) {
1786         throwSyntaxError("';' expected after switch-statement.");
1787       }
1788       getNextToken();
1789     } else {
1790       // '{' [labeled-statement-list] '}'
1791       if (token != TT_LISTOPEN) {
1792         throwSyntaxError("'{' expected in switch statement.");
1793       }
1794       getNextToken();
1795       if (token != TT_LISTCLOSE) {
1796         labeledStatementList();
1797       }
1798       if (token != TT_LISTCLOSE) {
1799         throwSyntaxError("'}' expected in switch statement.");
1800       }
1801       getNextToken();
1802
1803     }
1804   }
1805
1806   private void forStatement() throws CoreException {
1807     if (token == TT_DDOT) {
1808       getNextToken();
1809       statementList();
1810       if (token != TT_endfor) {
1811         throwSyntaxError("'endfor' expected.");
1812       }
1813       getNextToken();
1814       if (token != TT_SEMICOLON) {
1815         throwSyntaxError("';' expected after for-statement.");
1816       }
1817       getNextToken();
1818     } else {
1819       statement();
1820     }
1821   }
1822
1823   private void whileStatement() throws CoreException {
1824     // ':' statement-list 'endwhile' ';'
1825     if (token == TT_DDOT) {
1826       getNextToken();
1827       statementList();
1828       if (token != TT_endwhile) {
1829         throwSyntaxError("'endwhile' expected.");
1830       }
1831       getNextToken();
1832       if (token != TT_SEMICOLON) {
1833         throwSyntaxError("';' expected after while-statement.");
1834       }
1835       getNextToken();
1836     } else {
1837       statement();
1838     }
1839   }
1840
1841   private void foreachStatement() throws CoreException {
1842     if (token == TT_DDOT) {
1843       getNextToken();
1844       statementList();
1845       if (token != TT_endforeach) {
1846         throwSyntaxError("'endforeach' expected.");
1847       }
1848       getNextToken();
1849       if (token != TT_SEMICOLON) {
1850         throwSyntaxError("';' expected after foreach-statement.");
1851       }
1852       getNextToken();
1853     } else {
1854       statement();
1855     }
1856   }
1857
1858   private void exitStatus() throws CoreException {
1859     if (token == TT_ARGOPEN) {
1860       getNextToken();
1861     } else {
1862       throwSyntaxError("'(' expected in 'exit-status'.");
1863     }
1864     if (token != TT_ARGCLOSE) {
1865       expression();
1866     }
1867     if (token == TT_ARGCLOSE) {
1868       getNextToken();
1869     } else {
1870       throwSyntaxError("')' expected after 'exit-status'.");
1871     }
1872   }
1873
1874   private void expressionList() throws CoreException {
1875     do {
1876       expression();
1877       if (token == TT_COMMA) {
1878         getNextToken();
1879       } else {
1880         break;
1881       }
1882     } while (true);
1883   }
1884
1885   private void expression() throws CoreException {
1886     //    if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
1887     //      getNextToken();
1888     //    } else {
1889     logicalinclusiveorExpression();
1890     //      while (token != TT_SEMICOLON) {
1891     //        getNextToken();
1892     //      //      }
1893     //    }
1894   }
1895
1896   private void postfixExpression() throws CoreException {
1897     String ident;
1898     boolean castFlag = false;
1899     switch (token) {
1900       case TT_new :
1901         getNextToken();
1902         expression();
1903         break;
1904       case TT_null :
1905         getNextToken();
1906         break;
1907       case TT_false :
1908         getNextToken();
1909         break;
1910       case TT_true :
1911         getNextToken();
1912         break;
1913       case TT_STRING_CONSTANT :
1914         getNextToken();
1915         break;
1916       case TT_INTERPOLATED_STRING :
1917         getNextToken();
1918         break;
1919       case TT_ARGOPEN :
1920         getNextToken();
1921         if (token == TT_IDENTIFIER) {
1922           // check if identifier is a type:
1923           ident = identifier;
1924           String str = identifier.toLowerCase();
1925           for (int i = 0; i < PHP_TYPES.length; i++) {
1926             if (PHP_TYPES[i].equals(str)) {
1927               castFlag = true;
1928               break;
1929             }
1930           }
1931           if (castFlag) {
1932             getNextToken();
1933             if (token != TT_ARGCLOSE) {
1934               throwSyntaxError(") expected after cast-type '" + ident + "'.");
1935             }
1936             getNextToken();
1937             expression();
1938             break;
1939           }
1940         }
1941         if (!castFlag) {
1942           expression();
1943         }
1944         if (token != TT_ARGCLOSE) {
1945           throwSyntaxError(") expected in postfix-expression.");
1946         }
1947         getNextToken();
1948         break;
1949       case TT_DOUBLE_NUMBER :
1950         getNextToken();
1951         break;
1952       case TT_INT_NUMBER :
1953         getNextToken();
1954         break;
1955       case TT_DOLLAROPEN :
1956         getNextToken();
1957         expression();
1958         if (token != TT_LISTCLOSE) {
1959           throwSyntaxError("'}' expected after indirect variable token '${'.");
1960         }
1961         getNextToken();
1962         break;
1963       case TT_VARIABLE :
1964         ident = identifier;
1965         getNextToken();
1966         if (token == TT_LISTOPEN) {
1967           getNextToken();
1968           expression();
1969           if (token != TT_LISTCLOSE) {
1970             throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
1971           }
1972           getNextToken();
1973         } else if (token == TT_ARGOPEN) {
1974           getNextToken();
1975           if (token != TT_ARGCLOSE) {
1976             expressionList();
1977             if (token != TT_ARGCLOSE) {
1978               throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
1979             }
1980           }
1981           getNextToken();
1982         }
1983         break;
1984       case TT_IDENTIFIER :
1985         ident = identifier;
1986         getNextToken();
1987         if (token == TT_ARGOPEN) {
1988           getNextToken();
1989           if (token != TT_ARGCLOSE) {
1990             expressionList();
1991             if (token != TT_ARGCLOSE) {
1992               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
1993             }
1994           }
1995           getNextToken();
1996         }
1997         break;
1998       case TT_print :
1999         getNextToken();
2000         expression();
2001         //        if (token == TT_SEMICOLON) {
2002         //          getNextToken();
2003         //        } else {
2004         //          if (!phpEnd) {
2005         //            throwSyntaxError("';' expected after 'print' statement.");
2006         //          }
2007         //        }
2008         break;
2009       case TT_list :
2010         getNextToken();
2011         if (token == TT_ARGOPEN) {
2012           getNextToken();
2013           if (token == TT_COMMA) {
2014             getNextToken();
2015           }
2016           expressionList();
2017           if (token != TT_ARGCLOSE) {
2018             throwSyntaxError("')' expected after 'list' keyword.");
2019           }
2020           getNextToken();
2021           //          if (token == TT_SET) {
2022           //            getNextToken();
2023           //            logicalinclusiveorExpression();
2024           //          }
2025         } else {
2026           throwSyntaxError("'(' expected after 'list' keyword.");
2027         }
2028         break;
2029         //      case TT_exit :
2030         //        getNextToken();
2031         //        if (token != TT_SEMICOLON) {
2032         //          exitStatus();
2033         //        }
2034         //        if (token == TT_SEMICOLON) {
2035         //          getNextToken();
2036         //        } else {
2037         //          if (!phpEnd) {
2038         //            throwSyntaxError("';' expected after 'exit' expression.");
2039         //          }
2040         //        }
2041         //        break;
2042         //      case TT_die :
2043         //        getNextToken();
2044         //        if (token != TT_SEMICOLON) {
2045         //          exitStatus();
2046         //        }
2047         //        if (token == TT_SEMICOLON) {
2048         //          getNextToken();
2049         //        } else {
2050         //          if (!phpEnd) {
2051         //            throwSyntaxError("';' expected after 'die' expression.");
2052         //          }
2053         //        }
2054         //        break;
2055
2056         //      case TT_array :
2057         //        getNextToken();
2058         //        if (token == TT_ARGOPEN) {
2059         //          getNextToken();
2060         //          if (token == TT_COMMA) {
2061         //            getNextToken();
2062         //          }
2063         //          expressionList();
2064         //          if (token != TT_ARGCLOSE) {
2065         //            throwSyntaxError("')' expected after 'list' keyword.");
2066         //          }
2067         //          getNextToken();
2068         //          if (token == TT_SET) {
2069         //            getNextToken();
2070         //            logicalinclusiveorExpression();
2071         //          }
2072         //        } else {
2073         //          throwSyntaxError("'(' expected after 'list' keyword.");
2074         //        }
2075         //        break;
2076     }
2077     boolean while_flag = true;
2078     do {
2079       switch (token) {
2080         case TT_PARTOPEN :
2081           getNextToken();
2082           expression();
2083           if (token != TT_PARTCLOSE) {
2084             throwSyntaxError("] expected in postfix-expression.");
2085           }
2086           getNextToken();
2087           break;
2088         case TT_DDOT2 : // ::
2089         case TT_REF : // ->
2090           getNextToken();
2091           if (token > TT_KEYWORD) {
2092             ident = identifier;
2093             setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2094             getNextToken();
2095             if (token == TT_ARGOPEN) {
2096               getNextToken();
2097               expressionList();
2098               if (token != TT_ARGCLOSE) {
2099                 throwSyntaxError(") expected after identifier '" + ident + "'.");
2100               }
2101               getNextToken();
2102             }
2103             break;
2104           } else {
2105             switch (token) {
2106               case TT_VARIABLE :
2107                 ident = identifier;
2108                 getNextToken();
2109                 //              if (token == TT_ARGOPEN) {
2110                 //                getNextToken();
2111                 //                expressionList();
2112                 //                if (token != TT_ARGCLOSE) {
2113                 //                  throwSyntaxError(") expected after variable '" + ident + "'.");
2114                 //                }
2115                 //                getNextToken();
2116                 //              }
2117                 break;
2118               case TT_IDENTIFIER :
2119                 ident = identifier;
2120                 getNextToken();
2121                 if (token == TT_ARGOPEN) {
2122                   getNextToken();
2123                   expressionList();
2124                   if (token != TT_ARGCLOSE) {
2125                     throwSyntaxError(") expected after identifier '" + ident + "'.");
2126                   }
2127                   getNextToken();
2128                 }
2129                 break;
2130               case TT_LISTOPEN :
2131                 getNextToken();
2132                 expression();
2133                 if (token != TT_LISTCLOSE) {
2134                   throwSyntaxError("} expected in postfix-expression.");
2135                 }
2136                 getNextToken();
2137                 break;
2138               default :
2139                 throwSyntaxError("Syntax error after '->' token.");
2140             }
2141           }
2142           break;
2143         case TT_INCREMENT :
2144           getNextToken();
2145           break;
2146         case TT_DECREMENT :
2147           getNextToken();
2148           break;
2149         default :
2150           while_flag = false;
2151       }
2152
2153     } while (while_flag);
2154   }
2155
2156   private void unaryExpression() throws CoreException {
2157     switch (token) {
2158       case TT_INCREMENT :
2159         getNextToken();
2160         unaryExpression();
2161         break;
2162       case TT_DECREMENT :
2163         getNextToken();
2164         unaryExpression();
2165         break;
2166         // '@' '&' '*' '+' '-' '~' '!' 
2167       case TT_AT :
2168         getNextToken();
2169         castExpression();
2170         break;
2171       case TT_AMPERSAND :
2172         getNextToken();
2173         castExpression();
2174         break;
2175       case TT_MULTIPLY :
2176         getNextToken();
2177         castExpression();
2178         break;
2179       case TT_ADD :
2180         getNextToken();
2181         castExpression();
2182         break;
2183       case TT_SUBTRACT :
2184         getNextToken();
2185         castExpression();
2186         break;
2187       case TT_TILDE :
2188         getNextToken();
2189         castExpression();
2190         break;
2191       case TT_NOT :
2192         getNextToken();
2193         castExpression();
2194         break;
2195       default :
2196         postfixExpression();
2197     }
2198   }
2199
2200   private void castExpression() throws CoreException {
2201     //    if (token == TT_ARGOPEN) {
2202     //      getNextToken();
2203     //      typeName();
2204     //      if (token != TT_ARGCLOSE) {
2205     //        throwSyntaxError(") expected after cast-expression.");
2206     //      }
2207     //      getNextToken();
2208     //    }
2209     unaryExpression();
2210   }
2211
2212   private void typeName() throws CoreException {
2213     //'string' 'unset' 'array' 'object'
2214     //'bool' 'boolean'
2215     //'real' 'double' 'float'
2216     //'int' 'integer'
2217     String ident = "";
2218     if (token == TT_IDENTIFIER) {
2219       ident = identifier;
2220       String str = identifier.toLowerCase();
2221       getNextToken();
2222       for (int i = 0; i < PHP_TYPES.length; i++) {
2223         if (PHP_TYPES[i].equals(str)) {
2224           return;
2225         }
2226       }
2227     }
2228     throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
2229   }
2230
2231   private void assignExpression() throws CoreException {
2232     castExpression();
2233     if (token == TT_ASSIGN) { // =
2234       getNextToken();
2235       logicalinclusiveorExpression();
2236     } else if (token == TT_DOTASSIGN) { // .=
2237       getNextToken();
2238       logicalinclusiveorExpression();
2239     } else if (token == TT_FOREACH) { // =>
2240       getNextToken();
2241       logicalinclusiveorExpression();
2242     } else if (token == TT_ADDTO) { // +=
2243       getNextToken();
2244       logicalinclusiveorExpression();
2245     } else if (token == TT_SUBTRACTFROM) { // -=
2246       getNextToken();
2247       logicalinclusiveorExpression();
2248     } else if (token == TT_TIMESBY) { // *=
2249       getNextToken();
2250       logicalinclusiveorExpression();
2251     } else if (token == TT_DIVIDEBY) { // *=
2252       getNextToken();
2253       logicalinclusiveorExpression();
2254     } else if (token == TT_MODASSIGN) { // %=
2255       getNextToken();
2256       logicalinclusiveorExpression();
2257     } else if (token == TT_ANDASSIGN) { // &=
2258       getNextToken();
2259       logicalinclusiveorExpression();
2260     } else if (token == TT_POWASSIGN) { // ^=
2261       getNextToken();
2262       logicalinclusiveorExpression();
2263     } else if (token == TT_LSHIFTASSIGN) { // <<=
2264       getNextToken();
2265       logicalinclusiveorExpression();
2266     } else if (token == TT_RSHIFTASSIGN) { // >>=
2267       getNextToken();
2268       logicalinclusiveorExpression();
2269     } else if (token == TT_TILDEASSIGN) { // ~=
2270       getNextToken();
2271       logicalinclusiveorExpression();
2272     }
2273   }
2274
2275   private void multiplicativeExpression() throws CoreException {
2276     do {
2277       assignExpression();
2278       if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
2279         return;
2280       }
2281       getNextToken();
2282     } while (true);
2283   }
2284
2285   private void concatenationExpression() throws CoreException {
2286     do {
2287       multiplicativeExpression();
2288       if (token != TT_DOT) {
2289         return;
2290       }
2291       getNextToken();
2292     } while (true);
2293   }
2294
2295   private void additiveExpression() throws CoreException {
2296     do {
2297       concatenationExpression();
2298       if (token != TT_ADD && token != TT_SUBTRACT) {
2299         return;
2300       }
2301       getNextToken();
2302     } while (true);
2303   }
2304
2305   private void shiftExpression() throws CoreException {
2306     do {
2307       additiveExpression();
2308       if (token != TT_LSHIFT && token != TT_RSHIFT) {
2309         return;
2310       }
2311       getNextToken();
2312     } while (true);
2313   }
2314
2315   private void relationalExpression() throws CoreException {
2316     do {
2317       shiftExpression();
2318       if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
2319         return;
2320       }
2321       getNextToken();
2322     } while (true);
2323   }
2324
2325   private void identicalExpression() throws CoreException {
2326     do {
2327       relationalExpression();
2328       if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
2329         return;
2330       }
2331       getNextToken();
2332     } while (true);
2333   }
2334
2335   private void equalityExpression() throws CoreException {
2336     do {
2337       identicalExpression();
2338       if (token != TT_EQUAL && token != TT_UNEQUAL) {
2339         return;
2340       }
2341       getNextToken();
2342     } while (true);
2343   }
2344
2345   private void ternaryExpression() throws CoreException {
2346     equalityExpression();
2347     if (token == TT_QUESTIONMARK) {
2348       getNextToken();
2349       expression();
2350       if (token == TT_DDOT) {
2351         getNextToken();
2352         expression();
2353       } else {
2354         throwSyntaxError("':' expected in ternary operator '? :'.");
2355       }
2356     }
2357   }
2358
2359   private void andExpression() throws CoreException {
2360     do {
2361       ternaryExpression();
2362       if (token != TT_AMPERSAND) {
2363         return;
2364       }
2365       getNextToken();
2366     } while (true);
2367   }
2368
2369   private void exclusiveorExpression() throws CoreException {
2370     do {
2371       andExpression();
2372       if (token != TT_POW) {
2373         return;
2374       }
2375       getNextToken();
2376     } while (true);
2377   }
2378
2379   private void inclusiveorExpression() throws CoreException {
2380     do {
2381       exclusiveorExpression();
2382       if (token != TT_LINE) {
2383         return;
2384       }
2385       getNextToken();
2386     } while (true);
2387   }
2388
2389   private void booleanandExpression() throws CoreException {
2390     do {
2391       inclusiveorExpression();
2392       if (token != TT_AND) {
2393         return;
2394       }
2395       getNextToken();
2396     } while (true);
2397   }
2398
2399   private void booleanorExpression() throws CoreException {
2400     do {
2401       booleanandExpression();
2402       if (token != TT_OR) {
2403         return;
2404       }
2405       getNextToken();
2406     } while (true);
2407   }
2408
2409   private void logicalandExpression() throws CoreException {
2410     do {
2411       booleanorExpression();
2412       if (token != TT_and) {
2413         return;
2414       }
2415       getNextToken();
2416     } while (true);
2417   }
2418
2419   private void logicalexclusiveorExpression() throws CoreException {
2420     do {
2421       logicalandExpression();
2422       if (token != TT_xor) {
2423         return;
2424       }
2425       getNextToken();
2426     } while (true);
2427   }
2428
2429   private void logicalinclusiveorExpression() throws CoreException {
2430     do {
2431       logicalexclusiveorExpression();
2432       if (token != TT_or) {
2433         return;
2434       }
2435       getNextToken();
2436     } while (true);
2437   }
2438
2439   //  public void assignmentExpression() {
2440   //    if (token == TT_VARIABLE) {
2441   //      getNextToken();
2442   //      if (token == TT_SET) {
2443   //        getNextToken();
2444   //        logicalinclusiveorExpression();
2445   //      }
2446   //    } else {
2447   //      logicalinclusiveorExpression();
2448   //    }
2449   //  }
2450
2451   private void variableList() throws CoreException {
2452     do {
2453       variable();
2454       if (token == TT_COMMA) {
2455         getNextToken();
2456       } else {
2457         break;
2458       }
2459     } while (true);
2460   }
2461
2462   private void variable() throws CoreException {
2463     if (token == TT_DOLLAROPEN) {
2464       getNextToken();
2465       expression();
2466       ;
2467       if (token != TT_LISTCLOSE) {
2468         throwSyntaxError("'}' expected after indirect variable token '${'.");
2469       }
2470       getNextToken();
2471     } else {
2472       if (token == TT_VARIABLE) {
2473         getNextToken();
2474         if (token == TT_PARTOPEN) {
2475           getNextToken();
2476           expression();
2477           if (token != TT_PARTCLOSE) {
2478             throwSyntaxError("']' expected in variable-list.");
2479           }
2480           getNextToken();
2481         } else if (token == TT_ASSIGN) {
2482           getNextToken();
2483           constant();
2484         }
2485       } else {
2486         throwSyntaxError("$-variable expected in variable-list.");
2487       }
2488     }
2489   }
2490
2491   private void constant() throws CoreException {
2492     String ident;
2493     switch (token) {
2494       case TT_ADD :
2495         getNextToken();
2496         switch (token) {
2497           case TT_DOUBLE_NUMBER :
2498             getNextToken();
2499             break;
2500           case TT_INT_NUMBER :
2501             getNextToken();
2502             break;
2503           default :
2504             throwSyntaxError("Constant expected after '+' presign.");
2505         }
2506         break;
2507       case TT_SUBTRACT :
2508         getNextToken();
2509         switch (token) {
2510           case TT_DOUBLE_NUMBER :
2511             getNextToken();
2512             break;
2513           case TT_INT_NUMBER :
2514             getNextToken();
2515             break;
2516           default :
2517             throwSyntaxError("Constant expected after '-' presign.");
2518         }
2519         break;
2520       case TT_null :
2521         getNextToken();
2522         break;
2523       case TT_false :
2524         getNextToken();
2525         break;
2526       case TT_true :
2527         getNextToken();
2528         break;
2529       case TT_IDENTIFIER :
2530         ident = identifier;
2531         getNextToken();
2532         if (token == TT_ARGOPEN) {
2533           getNextToken();
2534           if (token != TT_ARGCLOSE) {
2535             expressionList();
2536             if (token != TT_ARGCLOSE) {
2537               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2538             }
2539           }
2540           getNextToken();
2541         }
2542         break;
2543       case TT_STRING_CONSTANT :
2544         getNextToken();
2545         break;
2546       case TT_INTERPOLATED_STRING :
2547         getNextToken();
2548         break;
2549       case TT_DOUBLE_NUMBER :
2550         getNextToken();
2551         break;
2552       case TT_INT_NUMBER :
2553         getNextToken();
2554         break;
2555       default :
2556         throwSyntaxError("Constant expected.");
2557     }
2558   }
2559   
2560   /**
2561    * Call the php parse command ( php -l -f &lt;filename&gt; )
2562    * and create markers according to the external parser output
2563    */
2564   public static void phpExternalParse(IFile file) {
2565     //IFile file = (IFile) resource;
2566     IPath path = file.getFullPath();
2567     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
2568     String filename = file.getLocation().toString();
2569
2570     String[] arguments = { filename };
2571     MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
2572     String command = form.format(arguments);
2573
2574     String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
2575
2576     try {
2577       // parse the buffer to find the errors and warnings
2578       createMarkers(parserResult, file);
2579     } catch (CoreException e) {
2580     }
2581   }
2582   
2583   /**
2584    * Create markers according to the external parser output
2585    */
2586   private static void createMarkers(String output, IFile file) throws CoreException {
2587     // delete all markers
2588     file.deleteMarkers(IMarker.PROBLEM, false, 0);
2589
2590     int indx = 0;
2591     int brIndx = 0;
2592     boolean flag = true;
2593     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
2594       // newer php error output (tested with 4.2.3)
2595       scanLine(output, file, indx, brIndx);
2596       indx = brIndx + 6;
2597       flag = false;
2598     }
2599     if (flag) {
2600       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
2601         // older php error output (tested with 4.2.3)
2602         scanLine(output, file, indx, brIndx);
2603         indx = brIndx + 4;
2604       }
2605     }
2606   }
2607   
2608   private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
2609     String current;
2610     String outLineNumberString;
2611     StringBuffer lineNumberBuffer = new StringBuffer(10);
2612     char ch;
2613     current = output.substring(indx, brIndx);
2614
2615     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
2616       int onLine = current.indexOf("on line <b>");
2617       if (onLine != -1) {
2618         lineNumberBuffer.delete(0, lineNumberBuffer.length());
2619         for (int i = onLine; i < current.length(); i++) {
2620           ch = current.charAt(i);
2621           if ('0' <= ch && '9' >= ch) {
2622             lineNumberBuffer.append(ch);
2623           }
2624         }
2625
2626         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
2627
2628         Hashtable attributes = new Hashtable();
2629
2630         current = current.replaceAll("\n", "");
2631         current = current.replaceAll("<b>", "");
2632         current = current.replaceAll("</b>", "");
2633         MarkerUtilities.setMessage(attributes, current);
2634
2635         if (current.indexOf(PARSE_ERROR_STRING) != -1)
2636           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
2637         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
2638           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
2639         else
2640           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
2641         MarkerUtilities.setLineNumber(attributes, lineNumber);
2642         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
2643       }
2644     }
2645   }
2646 }