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