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