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
 
   9     Klaus Hartlage - www.eclipseproject.de
 
  10 **********************************************************************/
 
  11 package net.sourceforge.phpeclipse.phpeditor.phpparser;
 
  13 import java.text.MessageFormat;
 
  14 import java.util.ArrayList;
 
  15 import java.util.HashMap;
 
  16 import java.util.Hashtable;
 
  18 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
  19 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
 
  20 import net.sourceforge.phpeclipse.phpeditor.PHPString;
 
  21 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
 
  22 import org.eclipse.core.resources.IFile;
 
  23 import org.eclipse.core.resources.IMarker;
 
  24 import org.eclipse.core.runtime.CoreException;
 
  25 import org.eclipse.core.runtime.IPath;
 
  26 import org.eclipse.jface.preference.IPreferenceStore;
 
  27 import org.eclipse.ui.texteditor.MarkerUtilities;
 
  29 public class PHPParser extends PHPKeywords {
 
  30   // strings for external parser call
 
  31   private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
 
  32   private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
 
  34   public static final int ERROR = 2;
 
  35   public static final int WARNING = 1;
 
  36   public static final int INFO = 0;
 
  37   private IFile fileToParse;
 
  38   private ArrayList phpList;
 
  40   private int currentPHPString;
 
  41   private boolean phpEnd;
 
  43   private static HashMap keywordMap = null;
 
  51   // row counter for syntax errors:
 
  53   // column counter for syntax errors:
 
  64   private String stringValue;
 
  66   /** Contains the current expression. */
 
  67   private StringBuffer expression;
 
  69   private boolean phpMode;
 
  71   final static int TT_EOF = 0;
 
  72   final static int TT_UNDEFINED = 1;
 
  73   final static int TT_HTML = 2;
 
  75   final static int TT_MOD = 30;
 
  76   final static int TT_NOT = 31;
 
  77   final static int TT_DOT = 32;
 
  78   final static int TT_POW = 33;
 
  79   final static int TT_DIV = 34;
 
  80   final static int TT_MULTIPLY = 35;
 
  81   final static int TT_SUBTRACT = 36;
 
  82   final static int TT_ADD = 37;
 
  83   final static int TT_EQUAL = 38;
 
  84   final static int TT_UNEQUAL = 39;
 
  85   final static int TT_GREATER = 40;
 
  86   final static int TT_GREATEREQUAL = 41;
 
  87   final static int TT_LESS = 42;
 
  88   final static int TT_LESSEQUAL = 43;
 
  89   final static int TT_AND = 44;
 
  90   final static int TT_OR = 45;
 
  91   final static int TT_HASH = 46;
 
  92   final static int TT_DDOT = 47;
 
  93   final static int TT_DOTASSIGN = 48;
 
  95   final static int TT_ASSIGN = 49;
 
  96   final static int TT_REF = 50;
 
  97   final static int TT_FOREACH = 51;
 
  98   final static int TT_AMPERSAND = 52;
 
  99   final static int TT_DOLLARLISTOPEN = 53;
 
 100   final static int TT_TILDE = 54;
 
 101   final static int TT_TILDEASSIGN = 55;
 
 102   final static int TT_MODASSIGN = 56;
 
 103   final static int TT_POWASSIGN = 57;
 
 104   final static int TT_RSHIFTASSIGN = 58;
 
 105   final static int TT_LSHIFTASSIGN = 59;
 
 106   final static int TT_ANDASSIGN = 60;
 
 107   final static int TT_QUESTIONMARK = 61;
 
 108   final static int TT_DDOT2 = 62;
 
 109   final static int TT_AT = 63;
 
 110   // final static int TT_HEREDOC = 64;
 
 112   final static int TT_DOLLAROPEN = 127;
 
 113   final static int TT_ARGOPEN = 128;
 
 114   final static int TT_ARGCLOSE = 129;
 
 115   final static int TT_LISTOPEN = 130;
 
 116   final static int TT_LISTCLOSE = 131;
 
 117   final static int TT_PARTOPEN = 132;
 
 118   final static int TT_PARTCLOSE = 133;
 
 119   final static int TT_COMMA = 134;
 
 121   final static int TT_STRING = 136;
 
 122   final static int TT_IDENTIFIER = 138;
 
 123   final static int TT_DIGIT = 139;
 
 124   final static int TT_SEMICOLON = 140;
 
 125   final static int TT_SLOT = 141;
 
 126   final static int TT_SLOTSEQUENCE = 142;
 
 127   final static int TT_DECREMENT = 144;
 
 128   final static int TT_INCREMENT = 145;
 
 129   final static int TT_ADDTO = 146;
 
 130   final static int TT_DIVIDEBY = 147;
 
 131   final static int TT_SUBTRACTFROM = 148;
 
 132   final static int TT_TIMESBY = 149;
 
 133   final static int TT_VARIABLE = 150;
 
 134   final static int TT_INT_NUMBER = 151;
 
 135   final static int TT_DOUBLE_NUMBER = 152;
 
 136   final static int TT_INTERPOLATED_STRING = 153;
 
 137   final static int TT_STRING_CONSTANT = 154;
 
 139   final static int TT_LSHIFT = 155;
 
 140   final static int TT_RSHIFT = 156;
 
 141   final static int TT_EX_EQUAL = 157;
 
 142   final static int TT_EX_UNEQUAL = 158;
 
 143   final static int TT_LINE = 159;
 
 144   //  final static int TT_AT = 153; // @
 
 149    *@param  sess  Description of Parameter
 
 152   public PHPParser(IFile fileToParse) {
 
 153     if (keywordMap == null) {
 
 154       keywordMap = new HashMap();
 
 155       for (int i = 0; i < PHP_KEYWORS.length; i++) {
 
 156         keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
 
 159     this.currentPHPString = 0;
 
 160     this.fileToParse = fileToParse;
 
 166     this.columnCount = 0;
 
 173    * Create marker for the parse error
 
 175   private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
 
 176     setMarker(fileToParse, message, lineNumber, errorLevel);
 
 179   public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
 
 181       Hashtable attributes = new Hashtable();
 
 182       MarkerUtilities.setMessage(attributes, message);
 
 183       switch (errorLevel) {
 
 185           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
 
 188           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
 
 191           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
 
 194       MarkerUtilities.setLineNumber(attributes, lineNumber);
 
 195       MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
 
 199   private void throwSyntaxError(String error) {
 
 201     if (str.length() < chIndx) {
 
 204     // read until end-of-line
 
 206     while (str.length() > eol) {
 
 207       ch = str.charAt(eol++);
 
 213     throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
 
 216   private void throwSyntaxError(String error, int startRow) {
 
 218     throw new SyntaxError(startRow, 0, " ", error);
 
 222    *  Method Declaration.
 
 226   private void getChar() {
 
 227     if (str.length() > chIndx) {
 
 228       ch = str.charAt(chIndx++);
 
 233     chIndx = str.length() + 1;
 
 239   private void getNextToken_OldVersion() throws CoreException {
 
 242     while (str.length() > chIndx) {
 
 243       ch = str.charAt(chIndx++);
 
 244       token = TT_UNDEFINED;
 
 247         columnCount = chIndx;
 
 248         continue; // while loop
 
 250       if (str.length() == chIndx) {
 
 253       if (!Character.isWhitespace(ch)) {
 
 255           if (str.length() > chIndx) {
 
 256             if (str.charAt(chIndx) == '{') {
 
 258               token = TT_DOLLAROPEN;
 
 265         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
 
 269         if (ch >= '0' && ch <= '9') {
 
 274           if (str.length() > chIndx) {
 
 275             if (str.charAt(chIndx) == '/') {
 
 277               // read comment until end of line:
 
 278               while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
 
 282             } else if (str.charAt(chIndx) == '*') {
 
 284               // multi line comment:
 
 285               while (str.length() > chIndx) {
 
 286                 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
 
 290                 ch = str.charAt(chIndx++);
 
 293                   columnCount = chIndx;
 
 299         } else if (ch == '#') {
 
 300           // read comment until end of line:
 
 301           while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
 
 305         } else if (ch == '"') {
 
 306           // read string until end
 
 307           boolean openString = true;
 
 308           while (str.length() > chIndx) {
 
 309             ch = str.charAt(chIndx++);
 
 311               if (str.length() > chIndx) {
 
 312                 ch = str.charAt(chIndx++);
 
 314             } else if (ch == '"') {
 
 317             } else if (ch == '\n') {
 
 319               columnCount = chIndx;
 
 323             throwSyntaxError("Open string character '\"' at end of file.");
 
 325           token = TT_INTERPOLATED_STRING;
 
 327         } else if (ch == '\'') {
 
 328           // read string until end
 
 329           boolean openString = true;
 
 330           int startRow = rowCount;
 
 331           while (str.length() > chIndx) {
 
 332             ch = str.charAt(chIndx++);
 
 334               if (str.length() > chIndx) {
 
 335                 ch = str.charAt(chIndx++);
 
 337             } else if (ch == '\'') {
 
 340             } else if (ch == '\n') {
 
 342               columnCount = chIndx;
 
 346             throwSyntaxError("Open string character \"'\" at end of file.", startRow);
 
 348           token = TT_STRING_CONSTANT;
 
 350         } else if (ch == '`') {
 
 351           // read string until end
 
 352           boolean openString = true;
 
 353           int startRow = rowCount;
 
 354           while (str.length() > chIndx) {
 
 355             ch = str.charAt(chIndx++);
 
 357               if (str.length() > chIndx) {
 
 358                 ch = str.charAt(chIndx++);
 
 360             } else if (ch == '`') {
 
 363             } else if (ch == '\n') {
 
 365               columnCount = chIndx;
 
 369             throwSyntaxError("Open string character \"`\" at end of file.", startRow);
 
 371           token = TT_STRING_CONSTANT;
 
 390             token = TT_LISTCLOSE;
 
 398             token = TT_PARTCLOSE;
 
 406             token = TT_QUESTIONMARK;
 
 413             if (str.length() > chIndx) {
 
 414               if (str.charAt(chIndx) == '=') {
 
 416                 token = TT_TILDEASSIGN;
 
 424             if (str.length() > chIndx) {
 
 425               if (str.charAt(chIndx) == '=') {
 
 427                 token = TT_DOTASSIGN;
 
 440             if (str.length() > chIndx) {
 
 441               if (str.charAt(chIndx) == '=') {
 
 443                 token = TT_MODASSIGN;
 
 450             token = TT_SEMICOLON;
 
 455             if (str.length() > chIndx) {
 
 456               if (str.charAt(chIndx) == '=') {
 
 458                 token = TT_POWASSIGN;
 
 467             if (str.length() > chIndx) {
 
 468               if (str.charAt(chIndx) == '=') {
 
 479             if (str.length() > chIndx) {
 
 480               if (str.charAt(chIndx) == '*') {
 
 486               if (str.charAt(chIndx) == '=') {
 
 497             if (str.length() > chIndx) {
 
 498               if (str.charAt(chIndx) == '+') {
 
 500                 token = TT_INCREMENT;
 
 504               if (str.charAt(chIndx) == '=') {
 
 514             if (str.length() > chIndx) {
 
 515               if (str.charAt(chIndx) == '-') {
 
 517                 token = TT_DECREMENT;
 
 521               if (str.charAt(chIndx) == '=') {
 
 523                 token = TT_SUBTRACTFROM;
 
 527               if (str.charAt(chIndx) == '>') {
 
 539             if (str.length() > chIndx) {
 
 540               ch = str.charAt(chIndx);
 
 545                 if (str.length() > chIndx) {
 
 546                   ch = str.charAt(chIndx);
 
 567             if (str.length() > chIndx) {
 
 568               if (str.charAt(chIndx) == '=') {
 
 571                 if (str.length() > chIndx) {
 
 572                   ch = str.charAt(chIndx);
 
 576                     token = TT_EX_UNEQUAL;
 
 587             if (str.length() > chIndx) {
 
 588               if (str.charAt(chIndx) == '=') {
 
 590                 token = TT_GREATEREQUAL;
 
 593               if (str.charAt(chIndx) == '>') {
 
 596                 if (str.length() > chIndx) {
 
 597                   if (str.charAt(chIndx) == '=') {
 
 599                     token = TT_RSHIFTASSIGN;
 
 611             if (str.length() > chIndx) {
 
 612               if (str.charAt(chIndx) == '=') {
 
 614                 token = TT_LESSEQUAL;
 
 618               if (str.charAt(chIndx) == '<') {
 
 621                 if (str.charAt(chIndx) == '<') {
 
 623                   int startRow = rowCount;
 
 624                   if (str.length() > chIndx) {
 
 626                     ch = str.charAt(++chIndx);
 
 627                     if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
 
 630                       token = TT_STRING_CONSTANT;
 
 631                       while (str.length() > chIndx) {
 
 632                         ch = str.charAt(chIndx++);
 
 634                           if (str.length() >= chIndx + identifier.length()) {
 
 635                             if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
 
 636                               chIndx += identifier.length();
 
 644                   throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
 
 645                 } else if (str.charAt(chIndx) == '=') {
 
 647                   token = TT_LSHIFTASSIGN;
 
 659             if (str.length() > chIndx) {
 
 660               if (str.charAt(chIndx) == '|') {
 
 670             token = TT_AMPERSAND;
 
 671             if (str.length() > chIndx) {
 
 672               if (str.charAt(chIndx) == '&') {
 
 677               if (str.charAt(chIndx) == '=') {
 
 679                 token = TT_ANDASSIGN;
 
 688             if (str.length() > chIndx) {
 
 689               if (str.charAt(chIndx) == ':') {
 
 704             throwSyntaxError("unexpected character: '" + ch + "'");
 
 707         if (token == TT_UNDEFINED) {
 
 708           throwSyntaxError("token not found");
 
 715     chIndx = str.length() + 1;
 
 720     if (phpList != null) {
 
 721       if (currentPHPString < phpList.size()) {
 
 722         token = TT_UNDEFINED;
 
 723         temp = (PHPString) phpList.get(currentPHPString++);
 
 724         this.str = temp.getPHPString();
 
 727         this.rowCount = temp.getLineNumber();
 
 728         this.columnCount = 0;
 
 732         token = TT_UNDEFINED;
 
 738    * gets the next token from input
 
 740   private void getNextToken() throws CoreException {
 
 741     boolean phpFound = false;
 
 748         while (str.length() > chIndx) {
 
 749           token = TT_UNDEFINED;
 
 750           ch = str.charAt(chIndx++);
 
 756             ch2 = str.charAt(chIndx++);
 
 758               ch2 = str.charAt(chIndx++);
 
 759               if (Character.isWhitespace(ch2)) {
 
 764               } else if (ch2 == 'p' || ch2 == 'P') {
 
 765                 ch2 = str.charAt(chIndx++);
 
 766                 if (ch2 == 'h' || ch2 == 'H') {
 
 767                   ch2 = str.charAt(chIndx++);
 
 768                   if (ch2 == 'p' || ch2 == 'P') {
 
 786         while (str.length() > chIndx) {
 
 787           ch = str.charAt(chIndx++);
 
 788           token = TT_UNDEFINED;
 
 791             columnCount = chIndx;
 
 792             continue; // while loop
 
 794           if (str.length() == chIndx) {
 
 797           if (!Character.isWhitespace(ch)) {
 
 799               if (str.length() > chIndx) {
 
 800                 if (str.charAt(chIndx) == '{') {
 
 802                   token = TT_DOLLAROPEN;
 
 809             if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
 
 813             if (ch >= '0' && ch <= '9') {
 
 818               if (str.length() > chIndx) {
 
 819                 if (str.charAt(chIndx) == '/') {
 
 822                   // read comment until end of line:
 
 823                   while ((str.length() > chIndx) && (ch != '\n')) {
 
 824                     ch = str.charAt(chIndx++);
 
 826                       ch2 = str.charAt(chIndx);
 
 840                 } else if (str.charAt(chIndx) == '*') {
 
 842                   // multi line comment:
 
 843                   while (str.length() > chIndx) {
 
 844                     if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
 
 848                     ch = str.charAt(chIndx++);
 
 851                       columnCount = chIndx;
 
 857             } else if (ch == '#') {
 
 858               // read comment until end of line:
 
 859               while ((str.length() > chIndx) && (ch != '\n')) {
 
 860                 ch = str.charAt(chIndx++);
 
 862                   ch2 = str.charAt(chIndx);
 
 876             } else if (ch == '"') {
 
 877               getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
 
 879             } else if (ch == '\'') {
 
 880               getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
 
 882             } else if (ch == '`') {
 
 883               getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
 
 884               setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
 
 903                 token = TT_LISTCLOSE;
 
 911                 token = TT_PARTCLOSE;
 
 919                 token = TT_QUESTIONMARK;
 
 920                 if (str.length() > chIndx) {
 
 921                   if (str.charAt(chIndx) == '>') {
 
 937                 if (str.length() > chIndx) {
 
 938                   if (str.charAt(chIndx) == '=') {
 
 940                     token = TT_TILDEASSIGN;
 
 948                 if (str.length() > chIndx) {
 
 949                   if (str.charAt(chIndx) == '=') {
 
 951                     token = TT_DOTASSIGN;
 
 964                 if (str.length() > chIndx) {
 
 965                   if (str.charAt(chIndx) == '=') {
 
 967                     token = TT_MODASSIGN;
 
 974                 token = TT_SEMICOLON;
 
 979                 if (str.length() > chIndx) {
 
 980                   if (str.charAt(chIndx) == '=') {
 
 982                     token = TT_POWASSIGN;
 
 991                 if (str.length() > chIndx) {
 
 992                   if (str.charAt(chIndx) == '=') {
 
1002                 token = TT_MULTIPLY;
 
1003                 if (str.length() > chIndx) {
 
1004                   if (str.charAt(chIndx) == '*') {
 
1010                   if (str.charAt(chIndx) == '=') {
 
1021                 if (str.length() > chIndx) {
 
1022                   if (str.charAt(chIndx) == '+') {
 
1024                     token = TT_INCREMENT;
 
1028                   if (str.charAt(chIndx) == '=') {
 
1037                 token = TT_SUBTRACT;
 
1038                 if (str.length() > chIndx) {
 
1039                   if (str.charAt(chIndx) == '-') {
 
1041                     token = TT_DECREMENT;
 
1045                   if (str.charAt(chIndx) == '=') {
 
1047                     token = TT_SUBTRACTFROM;
 
1051                   if (str.charAt(chIndx) == '>') {
 
1063                 if (str.length() > chIndx) {
 
1064                   ch = str.charAt(chIndx);
 
1069                     if (str.length() > chIndx) {
 
1070                       ch = str.charAt(chIndx);
 
1074                         token = TT_EX_EQUAL;
 
1091                 if (str.length() > chIndx) {
 
1092                   if (str.charAt(chIndx) == '=') {
 
1095                     if (str.length() > chIndx) {
 
1096                       ch = str.charAt(chIndx);
 
1100                         token = TT_EX_UNEQUAL;
 
1111                 if (str.length() > chIndx) {
 
1112                   if (str.charAt(chIndx) == '=') {
 
1114                     token = TT_GREATEREQUAL;
 
1117                   if (str.charAt(chIndx) == '>') {
 
1120                     if (str.length() > chIndx) {
 
1121                       if (str.charAt(chIndx) == '=') {
 
1123                         token = TT_RSHIFTASSIGN;
 
1135                 if (str.length() > chIndx) {
 
1136                   if (str.charAt(chIndx) == '=') {
 
1138                     token = TT_LESSEQUAL;
 
1142                   if (str.charAt(chIndx) == '<') {
 
1145                     if (str.charAt(chIndx) == '<') {
 
1147                       int startRow = rowCount;
 
1148                       if (str.length() > chIndx) {
 
1150                         ch = str.charAt(++chIndx);
 
1151                         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
 
1154                           token = TT_STRING_CONSTANT;
 
1155                           while (str.length() > chIndx) {
 
1156                             ch = str.charAt(chIndx++);
 
1158                               if (str.length() >= chIndx + identifier.length()) {
 
1159                                 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
 
1160                                   chIndx += identifier.length();
 
1168                       throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
 
1169                     } else if (str.charAt(chIndx) == '=') {
 
1171                       token = TT_LSHIFTASSIGN;
 
1183                 if (str.length() > chIndx) {
 
1184                   if (str.charAt(chIndx) == '|') {
 
1194                 token = TT_AMPERSAND;
 
1195                 if (str.length() > chIndx) {
 
1196                   if (str.charAt(chIndx) == '&') {
 
1201                   if (str.charAt(chIndx) == '=') {
 
1203                     token = TT_ANDASSIGN;
 
1212                 if (str.length() > chIndx) {
 
1213                   if (str.charAt(chIndx) == ':') {
 
1228                 throwSyntaxError("unexpected character: '" + ch + "'");
 
1231             if (token == TT_UNDEFINED) {
 
1232               throwSyntaxError("token not found");
 
1239     } catch (StringIndexOutOfBoundsException e) {
 
1240       // catched from charAt
 
1243     chIndx = str.length() + 1;
 
1248     //    if (phpList != null) {
 
1249     //      if (currentPHPString < phpList.size()) {
 
1250     //        token = TT_UNDEFINED;
 
1251     //        temp = (PHPString) phpList.get(currentPHPString++);
 
1252     //        this.str = temp.getPHPString();
 
1253     //        this.token = TT_EOF;
 
1255     //        this.rowCount = temp.getLineNumber();
 
1256     //        this.columnCount = 0;
 
1260     //        token = TT_UNDEFINED;
 
1267   private void getIdentifier() {
 
1268     StringBuffer ident = new StringBuffer();
 
1273       // attention recursive call:
 
1275       token = TT_VARIABLE;
 
1278       token = TT_IDENTIFIER;
 
1282     while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
 
1286     identifier = ident.toString();
 
1289     // determine if this identitfer is a keyword
 
1290     // @todo improve this in future version
 
1291     Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
 
1293       token = i.intValue();
 
1297   private void getNumber() {
 
1298     StringBuffer inum = new StringBuffer();
 
1307     // determine number conversions:
 
1308     if (firstCh == '0') {
 
1337     if (numFormat == 16) {
 
1338       while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
 
1343       while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
 
1344         if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
 
1345           if (ch == '.' && dFlag != ' ') {
 
1348           if ((dFlag == 'E') || (dFlag == 'e')) {
 
1354           if ((ch == '-') || (ch == '+')) {
 
1368         doubleNumber = new Double(inum.toString());
 
1369         token = TT_DOUBLE_NUMBER;
 
1372         longNumber = Long.valueOf(inum.toString(), numFormat);
 
1373         token = TT_INT_NUMBER;
 
1377     } catch (Throwable e) {
 
1378       throwSyntaxError("Number format error: " + inum.toString());
 
1384    * @param openChar the opening char ('\'', '"', '`')
 
1385    * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
 
1386    * @param errorMsg the error message in case of parse error in the string
 
1388   private void getString(final char openChar, final int typeString, final String errorMsg) {
 
1389     StringBuffer sBuffer = new StringBuffer();
 
1390     boolean openString = true;
 
1391     int startRow = rowCount;
 
1392     while (str.length() > chIndx) {
 
1393       ch = str.charAt(chIndx++);
 
1396         if (str.length() > chIndx) {
 
1397           ch = str.charAt(chIndx++);
 
1400       } else if (ch == openChar) {
 
1403       } else if (ch == '\n') {
 
1405         columnCount = chIndx;
 
1411       if (typeString == TT_STRING_CONSTANT) {
 
1412         throwSyntaxError(errorMsg, startRow);
 
1414         throwSyntaxError(errorMsg);
 
1418     stringValue = sBuffer.toString();
 
1421   public void htmlParserTester(String input) {
 
1423     int startLineNumber = 1;
 
1427     boolean phpMode = false;
 
1428     boolean phpFound = false;
 
1430     phpList = new ArrayList();
 
1431     currentPHPString = 0;
 
1435       while (i < input.length()) {
 
1436         ch = input.charAt(i++);
 
1440         if ((!phpMode) && ch == '<') {
 
1441           ch2 = input.charAt(i++);
 
1443             ch2 = input.charAt(i++);
 
1444             if (Character.isWhitespace(ch2)) {
 
1449               startLineNumber = lineNumber;
 
1451             } else if (ch2 == 'p') {
 
1452               ch2 = input.charAt(i++);
 
1454                 ch2 = input.charAt(i++);
 
1459                   startLineNumber = lineNumber;
 
1465             } else if (ch2 == 'P') {
 
1466               ch2 = input.charAt(i++);
 
1468                 ch2 = input.charAt(i++);
 
1473                   startLineNumber = lineNumber;
 
1486           if (ch == '/' && i < input.length()) {
 
1487             ch2 = input.charAt(i++);
 
1489               while (i < input.length()) {
 
1490                 ch = input.charAt(i++);
 
1491                 if (ch == '?' && i < input.length()) {
 
1492                   ch2 = input.charAt(i++);
 
1496                     phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
 
1500                 } else if (ch == '\n') {
 
1506             } else if (ch2 == '*') {
 
1507               // multi-line comment
 
1508               while (i < input.length()) {
 
1509                 ch = input.charAt(i++);
 
1512                 } else if (ch == '*' && i < input.length()) {
 
1513                   ch2 = input.charAt(i++);
 
1524           } else if (ch == '#') {
 
1525             while (i < input.length()) {
 
1526               ch = input.charAt(i++);
 
1527               if (ch == '?' && i < input.length()) {
 
1528                 ch2 = input.charAt(i++);
 
1532                   phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
 
1536               } else if (ch == '\n') {
 
1542           } else if (ch == '"') {
 
1544             while (i < input.length()) {
 
1545               ch = input.charAt(i++);
 
1548               } else if (ch == '\\' && i < input.length()) { // escape
 
1550               } else if (ch == '"') {
 
1555           } else if (ch == '\'') {
 
1557             while (i < input.length()) {
 
1558               ch = input.charAt(i++);
 
1561               } else if (ch == '\\' && i < input.length()) { // escape
 
1563               } else if (ch == '\'') {
 
1570           if (ch == '?' && i < input.length()) {
 
1571             ch2 = input.charAt(i++);
 
1575               phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
 
1584         setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
 
1587           setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
 
1588           phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
 
1590         //        for (int j=0;j<phpList.size();j++) {
 
1591         //          String temp = ((PHPString)phpList.get(j)).getPHPString();
 
1592         //          int startIndx = temp.length()-10;
 
1593         //          if (startIndx<0) {
 
1596         //          System.out.println(temp.substring(startIndx)+"?>");
 
1598         phpParserTester(null, 1);
 
1600         //        for(int j=0;j<phpList.size();j++) {
 
1601         //          temp = (PHPString) phpList.get(j);
 
1602         //          parser.start(temp.getPHPString(), temp.getLineNumber());
 
1605     } catch (CoreException e) {
 
1609   public void phpParserTester(String s, int rowCount) throws CoreException {
 
1612       if (phpList.size() != 0) {
 
1613         this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
 
1616     this.token = TT_EOF;
 
1618     this.rowCount = rowCount;
 
1619     this.columnCount = 0;
 
1620     this.phpEnd = false;
 
1621     this.phpMode = true;
 
1625         if (token != TT_EOF && token != TT_UNDEFINED) {
 
1628         if (token != TT_EOF && token != TT_UNDEFINED) {
 
1629           if (token == TT_ARGCLOSE) {
 
1630             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
 
1632           if (token == TT_LISTCLOSE) {
 
1633             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
 
1635           if (token == TT_PARTCLOSE) {
 
1636             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
 
1639           if (token == TT_ARGOPEN) {
 
1640             throwSyntaxError("Read character '('; end-of-file not reached.");
 
1642           if (token == TT_LISTOPEN) {
 
1643             throwSyntaxError("Read character '{';  end-of-file not reached.");
 
1645           if (token == TT_PARTOPEN) {
 
1646             throwSyntaxError("Read character '[';  end-of-file not reached.");
 
1649           throwSyntaxError("End-of-file not reached.");
 
1652       } catch (SyntaxError err) {
 
1656           setMarker(err.getMessage(), err.getLine(), ERROR);
 
1658         // if an error occured,
 
1659         // try to find keywords 'class' or 'function'
 
1660         // to parse the rest of the string
 
1661         while (token != TT_EOF && token != TT_UNDEFINED) {
 
1662           if (token == TT_class || token == TT_function) {
 
1667         if (token == TT_EOF || token == TT_UNDEFINED) {
 
1676    * Parses a string with php tags
 
1677    * i.e. '<body> <?php phpinfo() ?> </body>'
 
1679   public void parse(String s) throws CoreException {
 
1681     this.token = TT_EOF;
 
1684     this.columnCount = 0;
 
1685     this.phpEnd = false;
 
1686     this.phpMode = false;
 
1690         if (token != TT_EOF && token != TT_UNDEFINED) {
 
1693         if (token != TT_EOF && token != TT_UNDEFINED) {
 
1694           if (token == TT_ARGCLOSE) {
 
1695             throwSyntaxError("Too many closing ')'; end-of-file not reached.");
 
1697           if (token == TT_LISTCLOSE) {
 
1698             throwSyntaxError("Too many closing '}'; end-of-file not reached.");
 
1700           if (token == TT_PARTCLOSE) {
 
1701             throwSyntaxError("Too many closing ']'; end-of-file not reached.");
 
1704           if (token == TT_ARGOPEN) {
 
1705             throwSyntaxError("Read character '('; end-of-file not reached.");
 
1707           if (token == TT_LISTOPEN) {
 
1708             throwSyntaxError("Read character '{';  end-of-file not reached.");
 
1710           if (token == TT_PARTOPEN) {
 
1711             throwSyntaxError("Read character '[';  end-of-file not reached.");
 
1714           throwSyntaxError("End-of-file not reached.");
 
1717       } catch (SyntaxError sytaxErr1) {
 
1718         setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
 
1720           // if an error occured,
 
1721           // try to find keywords 'class' or 'function'
 
1722           // to parse the rest of the string
 
1723           while (token != TT_EOF && token != TT_UNDEFINED) {
 
1724             if (token == TT_class || token == TT_function) {
 
1729           if (token == TT_EOF || token == TT_UNDEFINED) {
 
1732         } catch (SyntaxError sytaxErr2) {
 
1733           setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
 
1741   public PHPOutlineInfo parseInfo(Object parent, String s) {
 
1742     PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
 
1743     //    Stack stack = new Stack();
 
1744     //    stack.push(outlineInfo.getDeclarations());
 
1747     this.token = TT_EOF;
 
1750     this.columnCount = 0;
 
1751     this.phpEnd = false;
 
1752     this.phpMode = false;
 
1756       parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
 
1757     } catch (CoreException e) {
 
1762   private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
 
1763     //   PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
 
1764     PHPSegmentWithChildren temp;
 
1766     String oldIdentifier;
 
1767     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
 
1769       while (token != TT_EOF && token != TT_UNDEFINED) {
 
1770         if (token == TT_VARIABLE) {
 
1771           outlineInfo.addVariable(identifier);
 
1773         } else if (token == TT_var) {
 
1775           if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
 
1777             outlineInfo.addVariable(identifier);
 
1778             if (token != TT_SEMICOLON) {
 
1779               oldIdentifier = identifier;
 
1782                 case TT_VARIABLE            : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
 
1784                 case TT_IDENTIFIER          : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
 
1786                 case TT_DOUBLE_NUMBER       : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
 
1788                 case TT_INT_NUMBER          : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
 
1790                 case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
 
1792                 case TT_STRING_CONSTANT     : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
 
1794                 default                     : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
 
1798               current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
 
1801         } else if (token == TT_function) {
 
1803           if (token == TT_AMPERSAND) {
 
1806           if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
 
1807             outlineInfo.addVariable(identifier);
 
1808             temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
 
1811             parseDeclarations(outlineInfo, temp, true);
 
1813         } else if (token == TT_class) {
 
1815           if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
 
1816             outlineInfo.addVariable(identifier);
 
1817             temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
 
1819             //        stack.push(temp);
 
1822             //skip tokens for classname, extends and others until we have the opening '{'
 
1823             while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
 
1826             parseDeclarations(outlineInfo, temp, true);
 
1829         } else if (token == TT_LISTOPEN) {
 
1832         } else if (token == TT_LISTCLOSE) {
 
1835           if (counter == 0 && goBack) {
 
1838         } else if (token == TT_require || token == TT_require_once || token == TT_include || token == TT_include_once) {
 
1840           outlineInfo.addVariable(identifier);
 
1841           current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
 
1847     } catch (CoreException e) {
 
1848     } catch (SyntaxError sytaxErr) {
 
1850         setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
 
1851       } catch (CoreException e) {
 
1856   private void statementList() throws CoreException {
 
1859       if ((token == TT_LISTCLOSE)
 
1860         || (token == TT_case)
 
1861         || (token == TT_default)
 
1862         || (token == TT_elseif)
 
1863         || (token == TT_endif)
 
1864         || (token == TT_endfor)
 
1865         || (token == TT_endforeach)
 
1866         || (token == TT_endwhile)
 
1867         || (token == TT_endswitch)
 
1868         || (token == TT_EOF)
 
1869         || (token == TT_UNDEFINED)) {
 
1875   private void compoundStatement() throws CoreException {
 
1876     // '{' [statement-list] '}'
 
1877     if (token == TT_LISTOPEN) {
 
1880       throwSyntaxError("'{' expected in compound-statement.");
 
1882     if (token != TT_LISTCLOSE) {
 
1885     if (token == TT_LISTCLOSE) {
 
1888       throwSyntaxError("'}' expected in compound-statement.");
 
1892   private void statement() throws CoreException {
 
1893     //   if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
 
1894     String keyword = identifier;
 
1895     if (token == TT_include || token == TT_include_once) {
 
1898       if (token == TT_SEMICOLON) {
 
1902           throwSyntaxError("';' character after 'include' or 'include_once' expected.");
 
1907     } else if (token == TT_require || token == TT_require_once) {
 
1911       if (token == TT_SEMICOLON) {
 
1915           throwSyntaxError("';' character after 'require' or 'require_once' expected.");
 
1920     } else if (token == TT_if) {
 
1922       if (token == TT_ARGOPEN) {
 
1925         throwSyntaxError("'(' expected after 'if' keyword.");
 
1928       if (token == TT_ARGCLOSE) {
 
1931         throwSyntaxError("')' expected after 'if' condition.");
 
1936     } else if (token == TT_switch) {
 
1938       if (token == TT_ARGOPEN) {
 
1941         throwSyntaxError("'(' expected after 'switch' keyword.");
 
1944       if (token == TT_ARGCLOSE) {
 
1947         throwSyntaxError("')' expected after 'switch' condition.");
 
1951     } else if (token == TT_for) {
 
1953       if (token == TT_ARGOPEN) {
 
1956         throwSyntaxError("'(' expected after 'for' keyword.");
 
1958       if (token == TT_SEMICOLON) {
 
1962         if (token == TT_SEMICOLON) {
 
1965           throwSyntaxError("';' expected after 'for'.");
 
1968       if (token == TT_SEMICOLON) {
 
1972         if (token == TT_SEMICOLON) {
 
1975           throwSyntaxError("';' expected after 'for'.");
 
1978       if (token == TT_ARGCLOSE) {
 
1982         if (token == TT_ARGCLOSE) {
 
1985           throwSyntaxError("')' expected after 'for'.");
 
1990     } else if (token == TT_while) {
 
1992       if (token == TT_ARGOPEN) {
 
1995         throwSyntaxError("'(' expected after 'while' keyword.");
 
1998       if (token == TT_ARGCLOSE) {
 
2001         throwSyntaxError("')' expected after 'while' condition.");
 
2005     } else if (token == TT_do) {
 
2007       if (token == TT_LISTOPEN) {
 
2010         throwSyntaxError("'{' expected after 'do' keyword.");
 
2012       if (token != TT_LISTCLOSE) {
 
2015       if (token == TT_LISTCLOSE) {
 
2018         throwSyntaxError("'}' expected after 'do' keyword.");
 
2020       if (token == TT_while) {
 
2022         if (token == TT_ARGOPEN) {
 
2025           throwSyntaxError("'(' expected after 'while' keyword.");
 
2028         if (token == TT_ARGCLOSE) {
 
2031           throwSyntaxError("')' expected after 'while' condition.");
 
2034         throwSyntaxError("'while' expected after 'do' keyword.");
 
2036       if (token == TT_SEMICOLON) {
 
2040           throwSyntaxError("';' expected after do-while statement.");
 
2045     } else if (token == TT_foreach) {
 
2047       if (token == TT_ARGOPEN) {
 
2050         throwSyntaxError("'(' expected after 'foreach' keyword.");
 
2053       if (token == TT_as) {
 
2056         throwSyntaxError("'as' expected after 'foreach' exxpression.");
 
2059       if (token == TT_FOREACH) {
 
2063       if (token == TT_ARGCLOSE) {
 
2066         throwSyntaxError("')' expected after 'foreach' expression.");
 
2071     } else if (token == TT_continue || token == TT_break || token == TT_return) {
 
2073       if (token != TT_SEMICOLON) {
 
2076       if (token == TT_SEMICOLON) {
 
2080           throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
 
2086     } else if (token == TT_echo) {
 
2089       if (token == TT_SEMICOLON) {
 
2093           throwSyntaxError("';' expected after 'echo' statement.");
 
2098       //    } else if (token == TT_print) {
 
2101       //      if (token == TT_SEMICOLON) {
 
2105       //          throwSyntaxError("';' expected after 'print' statement.");
 
2111     } else if (token == TT_global || token == TT_static) {
 
2114       if (token == TT_SEMICOLON) {
 
2118           throwSyntaxError("';' expected after 'global' or 'static' statement.");
 
2124       //      } else if (token == TT_unset) {
 
2126       //        if (token == TT_ARGOPEN) {
 
2129       //          throwSyntaxError("'(' expected after 'unset' keyword.");
 
2132       //        if (token == TT_ARGCLOSE) {
 
2135       //          throwSyntaxError("')' expected after 'unset' statement.");
 
2137       //        if (token == TT_SEMICOLON) {
 
2141       //            throwSyntaxError("';' expected after 'unset' statement.");
 
2147       //      } else if (token == TT_exit || token == TT_die) {
 
2149       //        if (token != TT_SEMICOLON) {
 
2152       //        if (token == TT_SEMICOLON) {
 
2156       //            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
 
2162     } else if (token == TT_define) {
 
2164       if (token == TT_ARGOPEN) {
 
2167         throwSyntaxError("'(' expected after 'define' keyword.");
 
2170       if (token == TT_COMMA) {
 
2173         throwSyntaxError("',' expected after first 'define' constant.");
 
2176       if (token == TT_COMMA) {
 
2180       if (token == TT_ARGCLOSE) {
 
2183         throwSyntaxError("')' expected after 'define' statement.");
 
2185       if (token == TT_SEMICOLON) {
 
2189           throwSyntaxError("';' expected after 'define' statement.");
 
2194     } else if (token == TT_function) {
 
2196       functionDefinition();
 
2198     } else if (token == TT_class) {
 
2204       //        throwSyntaxError("Unexpected keyword '" + keyword + "'");
 
2205     } else if (token == TT_LISTOPEN) {
 
2206       // compoundStatement
 
2208       if (token != TT_LISTCLOSE) {
 
2211       if (token == TT_LISTCLOSE) {
 
2215         throwSyntaxError("'}' expected.");
 
2218       if (token != TT_SEMICOLON) {
 
2221       if (token == TT_SEMICOLON) {
 
2226           throwSyntaxError("';' expected after expression.");
 
2233   private void classDeclarator() throws CoreException {
 
2235     //identifier 'extends' identifier
 
2236     if (token == TT_IDENTIFIER) {
 
2238       if (token == TT_extends) {
 
2240         if (token == TT_IDENTIFIER) {
 
2243           throwSyntaxError("Class name expected after keyword 'extends'.");
 
2247       throwSyntaxError("Class name expected after keyword 'class'.");
 
2251   private void classBody() throws CoreException {
 
2252     //'{' [class-element-list] '}'
 
2253     if (token == TT_LISTOPEN) {
 
2255       if (token != TT_LISTCLOSE) {
 
2258       if (token == TT_LISTCLOSE) {
 
2261         throwSyntaxError("'}' expected at end of class body.");
 
2264       throwSyntaxError("'{' expected at start of class body.");
 
2268   private void classElementList() throws CoreException {
 
2271     } while (token == TT_function || token == TT_var);
 
2274   private void classElement() throws CoreException {
 
2276     //function-definition
 
2277     if (token == TT_function) {
 
2279       functionDefinition();
 
2280     } else if (token == TT_var) {
 
2284       throwSyntaxError("'function' or 'var' expected.");
 
2288   private void classProperty() throws CoreException {
 
2289     //'var' variable ';'
 
2290     //'var' variable '=' constant ';'
 
2292       if (token == TT_VARIABLE) {
 
2294         if (token == TT_ASSIGN) {
 
2299         throwSyntaxError("Variable expected after keyword 'var'.");
 
2301       if (token != TT_COMMA) {
 
2306     if (token == TT_SEMICOLON) {
 
2309       throwSyntaxError("';' expected after variable declaration.");
 
2313   private void functionDefinition() throws CoreException {
 
2314     functionDeclarator();
 
2315     compoundStatement();
 
2318   private void functionDeclarator() throws CoreException {
 
2319     //identifier '(' [parameter-list] ')'
 
2320     if (token == TT_AMPERSAND) {
 
2323     if (token == TT_IDENTIFIER) {
 
2325       if (token == TT_ARGOPEN) {
 
2328         throwSyntaxError("'(' expected in function declaration.");
 
2330       if (token != TT_ARGCLOSE) {
 
2333       if (token != TT_ARGCLOSE) {
 
2334         throwSyntaxError("')' expected in function declaration.");
 
2341   private void parameterList() throws CoreException {
 
2342     //parameter-declaration
 
2343     //parameter-list ',' parameter-declaration
 
2345       parameterDeclaration();
 
2346       if (token != TT_COMMA) {
 
2353   private void parameterDeclaration() throws CoreException {
 
2355     //variable-reference
 
2356     if (token == TT_AMPERSAND) {
 
2358       if (token == TT_VARIABLE) {
 
2361         throwSyntaxError("Variable expected after reference operator '&'.");
 
2364     //variable '=' constant
 
2365     if (token == TT_VARIABLE) {
 
2367       if (token == TT_ASSIGN) {
 
2375   private void labeledStatementList() throws CoreException {
 
2376     if (token != TT_case && token != TT_default) {
 
2377       throwSyntaxError("'case' or 'default' expected.");
 
2380       if (token == TT_case) {
 
2383         if (token == TT_DDOT) {
 
2385           if (token == TT_case || token == TT_default) { // empty case statement ?
 
2389         } else if (token == TT_SEMICOLON) {
 
2390           setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
 
2392           if (token == TT_case) { // empty case statement ?
 
2397           throwSyntaxError("':' character after 'case' constant expected.");
 
2399       } else { // TT_default
 
2401         if (token == TT_DDOT) {
 
2405           throwSyntaxError("':' character after 'default' expected.");
 
2408     } while (token == TT_case || token == TT_default);
 
2411   //  public void labeledStatement() {
 
2412   //    if (token == TT_case) {
 
2415   //      if (token == TT_DDOT) {
 
2419   //        throwSyntaxError("':' character after 'case' constant expected.");
 
2422   //    } else if (token == TT_default) {
 
2424   //      if (token == TT_DDOT) {
 
2428   //        throwSyntaxError("':' character after 'default' expected.");
 
2434   //  public void expressionStatement() {
 
2437   //  private void inclusionStatement() {
 
2440   //  public void compoundStatement() {
 
2443   //  public void selectionStatement() {
 
2446   //  public void iterationStatement() {
 
2449   //  public void jumpStatement() {
 
2452   //  public void outputStatement() {
 
2455   //  public void scopeStatement() {
 
2458   //  public void flowStatement() {
 
2461   //  public void definitionStatement() {
 
2464   private void ifStatement() throws CoreException {
 
2465     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
 
2466     if (token == TT_DDOT) {
 
2472           if (token == TT_DDOT) {
 
2476             if (token == TT_if) { //'else if'
 
2478               elseifStatementList();
 
2480               throwSyntaxError("':' expected after 'else'.");
 
2486           elseifStatementList();
 
2490       if (token != TT_endif) {
 
2491         throwSyntaxError("'endif' expected.");
 
2494       if (token != TT_SEMICOLON) {
 
2495         throwSyntaxError("';' expected after if-statement.");
 
2499       // statement [else-statement]
 
2501       if (token == TT_elseif) {
 
2503         if (token == TT_ARGOPEN) {
 
2506           throwSyntaxError("'(' expected after 'elseif' keyword.");
 
2509         if (token == TT_ARGCLOSE) {
 
2512           throwSyntaxError("')' expected after 'elseif' condition.");
 
2515       } else if (token == TT_else) {
 
2522   private void elseifStatementList() throws CoreException {
 
2528           if (token == TT_DDOT) {
 
2533             if (token == TT_if) { //'else if'
 
2536               throwSyntaxError("':' expected after 'else'.");
 
2549   private void elseifStatement() throws CoreException {
 
2550     if (token == TT_ARGOPEN) {
 
2553       if (token != TT_ARGOPEN) {
 
2554         throwSyntaxError("')' expected in else-if-statement.");
 
2557       if (token != TT_DDOT) {
 
2558         throwSyntaxError("':' expected in else-if-statement.");
 
2565   private void switchStatement() throws CoreException {
 
2566     if (token == TT_DDOT) {
 
2567       // ':' [labeled-statement-list] 'endswitch' ';'
 
2569       labeledStatementList();
 
2570       if (token != TT_endswitch) {
 
2571         throwSyntaxError("'endswitch' expected.");
 
2574       if (token != TT_SEMICOLON) {
 
2575         throwSyntaxError("';' expected after switch-statement.");
 
2579       // '{' [labeled-statement-list] '}'
 
2580       if (token != TT_LISTOPEN) {
 
2581         throwSyntaxError("'{' expected in switch statement.");
 
2584       if (token != TT_LISTCLOSE) {
 
2585         labeledStatementList();
 
2587       if (token != TT_LISTCLOSE) {
 
2588         throwSyntaxError("'}' expected in switch statement.");
 
2595   private void forStatement() throws CoreException {
 
2596     if (token == TT_DDOT) {
 
2599       if (token != TT_endfor) {
 
2600         throwSyntaxError("'endfor' expected.");
 
2603       if (token != TT_SEMICOLON) {
 
2604         throwSyntaxError("';' expected after for-statement.");
 
2612   private void whileStatement() throws CoreException {
 
2613     // ':' statement-list 'endwhile' ';'
 
2614     if (token == TT_DDOT) {
 
2617       if (token != TT_endwhile) {
 
2618         throwSyntaxError("'endwhile' expected.");
 
2621       if (token != TT_SEMICOLON) {
 
2622         throwSyntaxError("';' expected after while-statement.");
 
2630   private void foreachStatement() throws CoreException {
 
2631     if (token == TT_DDOT) {
 
2634       if (token != TT_endforeach) {
 
2635         throwSyntaxError("'endforeach' expected.");
 
2638       if (token != TT_SEMICOLON) {
 
2639         throwSyntaxError("';' expected after foreach-statement.");
 
2647   private void exitStatus() throws CoreException {
 
2648     if (token == TT_ARGOPEN) {
 
2651       throwSyntaxError("'(' expected in 'exit-status'.");
 
2653     if (token != TT_ARGCLOSE) {
 
2656     if (token == TT_ARGCLOSE) {
 
2659       throwSyntaxError("')' expected after 'exit-status'.");
 
2663   private void expressionList() throws CoreException {
 
2666       if (token == TT_COMMA) {
 
2674   private void expression() throws CoreException {
 
2675     //todo: find a better way to get the expression
 
2676     expression = new StringBuffer();
 
2677     for (int i = chIndx;i<str.length();i++) {
 
2678       if (str.charAt(i) == ';') {
 
2681       expression.append(str.charAt(i));
 
2683     //    if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
 
2686     logicalinclusiveorExpression();
 
2687     //      while (token != TT_SEMICOLON) {
 
2693   private void postfixExpression() throws CoreException {
 
2695     boolean castFlag = false;
 
2710       case TT_STRING_CONSTANT :
 
2713       case TT_INTERPOLATED_STRING :
 
2718         if (token == TT_IDENTIFIER) {
 
2719           // check if identifier is a type:
 
2721           String str = identifier.toLowerCase();
 
2722           for (int i = 0; i < PHP_TYPES.length; i++) {
 
2723             if (PHP_TYPES[i].equals(str)) {
 
2730             if (token != TT_ARGCLOSE) {
 
2731               throwSyntaxError(") expected after cast-type '" + ident + "'.");
 
2741         if (token != TT_ARGCLOSE) {
 
2742           throwSyntaxError(") expected in postfix-expression.");
 
2746       case TT_DOUBLE_NUMBER :
 
2749       case TT_INT_NUMBER :
 
2752       case TT_DOLLAROPEN :
 
2755         if (token != TT_LISTCLOSE) {
 
2756           throwSyntaxError("'}' expected after indirect variable token '${'.");
 
2763         if (token == TT_LISTOPEN) {
 
2766           if (token != TT_LISTCLOSE) {
 
2767             throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
 
2770         } else if (token == TT_ARGOPEN) {
 
2772           if (token != TT_ARGCLOSE) {
 
2774             if (token != TT_ARGCLOSE) {
 
2775               throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
 
2781       case TT_IDENTIFIER :
 
2784         if (token == TT_ARGOPEN) {
 
2786           if (token != TT_ARGCLOSE) {
 
2788             if (token != TT_ARGCLOSE) {
 
2789               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
 
2798         //        if (token == TT_SEMICOLON) {
 
2802         //            throwSyntaxError("';' expected after 'print' statement.");
 
2809         if (token == TT_ARGOPEN) {
 
2811           if (token == TT_COMMA) {
 
2815           if (token != TT_ARGCLOSE) {
 
2816             throwSyntaxError("')' expected after 'list' keyword.");
 
2819           //          if (token == TT_SET) {
 
2821           //            logicalinclusiveorExpression();
 
2824           throwSyntaxError("'(' expected after 'list' keyword.");
 
2829         //        if (token != TT_SEMICOLON) {
 
2832         //        if (token == TT_SEMICOLON) {
 
2836         //            throwSyntaxError("';' expected after 'exit' expression.");
 
2843         //        if (token != TT_SEMICOLON) {
 
2846         //        if (token == TT_SEMICOLON) {
 
2850         //            throwSyntaxError("';' expected after 'die' expression.");
 
2857         //        if (token == TT_ARGOPEN) {
 
2859         //          if (token == TT_COMMA) {
 
2862         //          expressionList();
 
2863         //          if (token != TT_ARGCLOSE) {
 
2864         //            throwSyntaxError("')' expected after 'list' keyword.");
 
2867         //          if (token == TT_SET) {
 
2869         //            logicalinclusiveorExpression();
 
2872         //          throwSyntaxError("'(' expected after 'list' keyword.");
 
2876     boolean while_flag = true;
 
2882           if (token != TT_PARTCLOSE) {
 
2883             throwSyntaxError("] expected in postfix-expression.");
 
2887         case TT_DDOT2 : // ::
 
2890           if (token > TT_KEYWORD) {
 
2892             setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
 
2898               //              if (token == TT_ARGOPEN) {
 
2900               //                expressionList();
 
2901               //                if (token != TT_ARGCLOSE) {
 
2902               //                  throwSyntaxError(") expected after variable '" + ident + "'.");
 
2907             case TT_IDENTIFIER :
 
2914               if (token != TT_LISTCLOSE) {
 
2915                 throwSyntaxError("} expected in postfix-expression.");
 
2920               throwSyntaxError("Syntax error after '->' token.");
 
2921           } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
 
2922               if (token == TT_PARTOPEN) {
 
2925                 if (token != TT_PARTCLOSE) {
 
2926                   throwSyntaxError("] expected after '->'.");
 
2930               if (token == TT_ARGOPEN) {
 
2933                 if (token != TT_ARGCLOSE) {
 
2934                   throwSyntaxError(") expected after '->'.");
 
2938               if (token == TT_LISTOPEN) {
 
2941                 if (token != TT_LISTCLOSE) {
 
2942                   throwSyntaxError("} expected after '->'.");
 
2962   private void unaryExpression() throws CoreException {
 
2972         // '@' '&' '*' '+' '-' '~' '!'
 
3002         postfixExpression();
 
3006   private void castExpression() throws CoreException {
 
3007     //    if (token == TT_ARGOPEN) {
 
3010     //      if (token != TT_ARGCLOSE) {
 
3011     //        throwSyntaxError(") expected after cast-expression.");
 
3018   private void typeName() throws CoreException {
 
3019     //'string' 'unset' 'array' 'object'
 
3021     //'real' 'double' 'float'
 
3024     if (token == TT_IDENTIFIER) {
 
3026       String str = identifier.toLowerCase();
 
3028       for (int i = 0; i < PHP_TYPES.length; i++) {
 
3029         if (PHP_TYPES[i].equals(str)) {
 
3034     throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
 
3037   private void assignExpression() throws CoreException {
 
3039     if (token == TT_ASSIGN) { // =
 
3041       logicalinclusiveorExpression();
 
3042     } else if (token == TT_DOTASSIGN) { // .=
 
3044       logicalinclusiveorExpression();
 
3045     } else if (token == TT_FOREACH) { // =>
 
3047       logicalinclusiveorExpression();
 
3048     } else if (token == TT_ADDTO) { // +=
 
3050       logicalinclusiveorExpression();
 
3051     } else if (token == TT_SUBTRACTFROM) { // -=
 
3053       logicalinclusiveorExpression();
 
3054     } else if (token == TT_TIMESBY) { // *=
 
3056       logicalinclusiveorExpression();
 
3057     } else if (token == TT_DIVIDEBY) { // *=
 
3059       logicalinclusiveorExpression();
 
3060     } else if (token == TT_MODASSIGN) { // %=
 
3062       logicalinclusiveorExpression();
 
3063     } else if (token == TT_ANDASSIGN) { // &=
 
3065       logicalinclusiveorExpression();
 
3066     } else if (token == TT_POWASSIGN) { // ^=
 
3068       logicalinclusiveorExpression();
 
3069     } else if (token == TT_LSHIFTASSIGN) { // <<=
 
3071       logicalinclusiveorExpression();
 
3072     } else if (token == TT_RSHIFTASSIGN) { // >>=
 
3074       logicalinclusiveorExpression();
 
3075     } else if (token == TT_TILDEASSIGN) { // ~=
 
3077       logicalinclusiveorExpression();
 
3081   private void multiplicativeExpression() throws CoreException {
 
3084       if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
 
3091   private void concatenationExpression() throws CoreException {
 
3093       multiplicativeExpression();
 
3094       if (token != TT_DOT) {
 
3101   private void additiveExpression() throws CoreException {
 
3103       concatenationExpression();
 
3104       if (token != TT_ADD && token != TT_SUBTRACT) {
 
3111   private void shiftExpression() throws CoreException {
 
3113       additiveExpression();
 
3114       if (token != TT_LSHIFT && token != TT_RSHIFT) {
 
3121   private void relationalExpression() throws CoreException {
 
3124       if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
 
3131   private void identicalExpression() throws CoreException {
 
3133       relationalExpression();
 
3134       if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
 
3141   private void equalityExpression() throws CoreException {
 
3143       identicalExpression();
 
3144       if (token != TT_EQUAL && token != TT_UNEQUAL) {
 
3151   private void ternaryExpression() throws CoreException {
 
3152     equalityExpression();
 
3153     if (token == TT_QUESTIONMARK) {
 
3156       if (token == TT_DDOT) {
 
3160         throwSyntaxError("':' expected in ternary operator '? :'.");
 
3165   private void andExpression() throws CoreException {
 
3167       ternaryExpression();
 
3168       if (token != TT_AMPERSAND) {
 
3175   private void exclusiveorExpression() throws CoreException {
 
3178       if (token != TT_POW) {
 
3185   private void inclusiveorExpression() throws CoreException {
 
3187       exclusiveorExpression();
 
3188       if (token != TT_LINE) {
 
3195   private void booleanandExpression() throws CoreException {
 
3197       inclusiveorExpression();
 
3198       if (token != TT_AND) {
 
3205   private void booleanorExpression() throws CoreException {
 
3207       booleanandExpression();
 
3208       if (token != TT_OR) {
 
3215   private void logicalandExpression() throws CoreException {
 
3217       booleanorExpression();
 
3218       if (token != TT_and) {
 
3225   private void logicalexclusiveorExpression() throws CoreException {
 
3227       logicalandExpression();
 
3228       if (token != TT_xor) {
 
3235   private void logicalinclusiveorExpression() throws CoreException {
 
3237       logicalexclusiveorExpression();
 
3238       if (token != TT_or) {
 
3245   //  public void assignmentExpression() {
 
3246   //    if (token == TT_VARIABLE) {
 
3248   //      if (token == TT_SET) {
 
3250   //        logicalinclusiveorExpression();
 
3253   //      logicalinclusiveorExpression();
 
3257   private void variableList() throws CoreException {
 
3260       if (token == TT_COMMA) {
 
3268   private void variable() throws CoreException {
 
3269     if (token == TT_DOLLAROPEN) {
 
3273       if (token != TT_LISTCLOSE) {
 
3274         throwSyntaxError("'}' expected after indirect variable token '${'.");
 
3278       if (token == TT_VARIABLE) {
 
3280         if (token == TT_PARTOPEN) {
 
3283           if (token != TT_PARTCLOSE) {
 
3284             throwSyntaxError("']' expected in variable-list.");
 
3287         } else if (token == TT_ASSIGN) {
 
3292         throwSyntaxError("$-variable expected in variable-list.");
 
3297   private void constant() throws CoreException {
 
3303           case TT_DOUBLE_NUMBER :
 
3306           case TT_INT_NUMBER :
 
3310             throwSyntaxError("Constant expected after '+' presign.");
 
3316           case TT_DOUBLE_NUMBER :
 
3319           case TT_INT_NUMBER :
 
3323             throwSyntaxError("Constant expected after '-' presign.");
 
3335       case TT_IDENTIFIER :
 
3338         if (token == TT_ARGOPEN) {
 
3340           if (token != TT_ARGCLOSE) {
 
3342             if (token != TT_ARGCLOSE) {
 
3343               throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
 
3349       case TT_STRING_CONSTANT :
 
3352       case TT_INTERPOLATED_STRING :
 
3355       case TT_DOUBLE_NUMBER :
 
3358       case TT_INT_NUMBER :
 
3362         throwSyntaxError("Constant expected.");
 
3367    * Call the php parse command ( php -l -f <filename> )
 
3368    * and create markers according to the external parser output
 
3370   public static void phpExternalParse(IFile file) {
 
3371     //IFile file = (IFile) resource;
 
3372     IPath path = file.getFullPath();
 
3373     IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
 
3374     String filename = file.getLocation().toString();
 
3376     String[] arguments = { filename };
 
3377     MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
 
3378     String command = form.format(arguments);
 
3380     String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
 
3383       // parse the buffer to find the errors and warnings
 
3384       createMarkers(parserResult, file);
 
3385     } catch (CoreException e) {
 
3390    * Create markers according to the external parser output
 
3392   private static void createMarkers(String output, IFile file) throws CoreException {
 
3393     // delete all markers
 
3394     file.deleteMarkers(IMarker.PROBLEM, false, 0);
 
3398     boolean flag = true;
 
3399     while ((brIndx = output.indexOf("<br />", indx)) != -1) {
 
3400       // newer php error output (tested with 4.2.3)
 
3401       scanLine(output, file, indx, brIndx);
 
3406       while ((brIndx = output.indexOf("<br>", indx)) != -1) {
 
3407         // older php error output (tested with 4.2.3)
 
3408         scanLine(output, file, indx, brIndx);
 
3414   private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
 
3416     String outLineNumberString;
 
3417     StringBuffer lineNumberBuffer = new StringBuffer(10);
 
3419     current = output.substring(indx, brIndx);
 
3421     if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
 
3422       int onLine = current.indexOf("on line <b>");
 
3424         lineNumberBuffer.delete(0, lineNumberBuffer.length());
 
3425         for (int i = onLine; i < current.length(); i++) {
 
3426           ch = current.charAt(i);
 
3427           if ('0' <= ch && '9' >= ch) {
 
3428             lineNumberBuffer.append(ch);
 
3432         int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
 
3434         Hashtable attributes = new Hashtable();
 
3436         current = current.replaceAll("\n", "");
 
3437         current = current.replaceAll("<b>", "");
 
3438         current = current.replaceAll("</b>", "");
 
3439         MarkerUtilities.setMessage(attributes, current);
 
3441         if (current.indexOf(PARSE_ERROR_STRING) != -1)
 
3442           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
 
3443         else if (current.indexOf(PARSE_WARNING_STRING) != -1)
 
3444           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
 
3446           attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
 
3447         MarkerUtilities.setLineNumber(attributes, lineNumber);
 
3448         MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);