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