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