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') {
765 ch2 = str.charAt(chIndx++);
767 ch2 = str.charAt(chIndx++);
776 } else if (ch2 == 'P') {
777 ch2 = str.charAt(chIndx++);
779 ch2 = str.charAt(chIndx++);
798 while (str.length() > chIndx) {
799 ch = str.charAt(chIndx++);
800 token = TT_UNDEFINED;
803 columnCount = chIndx;
804 continue; // while loop
806 if (str.length() == chIndx) {
809 if (!Character.isWhitespace(ch)) {
811 if (str.length() > chIndx) {
812 if (str.charAt(chIndx) == '{') {
814 token = TT_DOLLAROPEN;
821 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
825 if (ch >= '0' && ch <= '9') {
830 if (str.length() > chIndx) {
831 if (str.charAt(chIndx) == '/') {
834 // read comment until end of line:
835 while ((str.length() > chIndx) && (ch != '\n')) {
836 ch = str.charAt(chIndx++);
838 ch2 = str.charAt(chIndx);
852 } else if (str.charAt(chIndx) == '*') {
854 // multi line comment:
855 while (str.length() > chIndx) {
856 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
860 ch = str.charAt(chIndx++);
863 columnCount = chIndx;
869 } else if (ch == '#') {
870 // read comment until end of line:
871 while ((str.length() > chIndx) && (ch != '\n')) {
872 ch = str.charAt(chIndx++);
874 ch2 = str.charAt(chIndx);
888 } else if (ch == '"') {
889 getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
891 } else if (ch == '\'') {
892 getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
894 } else if (ch == '`') {
895 getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
896 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
915 token = TT_LISTCLOSE;
923 token = TT_PARTCLOSE;
931 token = TT_QUESTIONMARK;
932 if (str.length() > chIndx) {
933 if (str.charAt(chIndx) == '>') {
949 if (str.length() > chIndx) {
950 if (str.charAt(chIndx) == '=') {
952 token = TT_TILDEASSIGN;
960 if (str.length() > chIndx) {
961 if (str.charAt(chIndx) == '=') {
963 token = TT_DOTASSIGN;
976 if (str.length() > chIndx) {
977 if (str.charAt(chIndx) == '=') {
979 token = TT_MODASSIGN;
986 token = TT_SEMICOLON;
991 if (str.length() > chIndx) {
992 if (str.charAt(chIndx) == '=') {
994 token = TT_POWASSIGN;
1003 if (str.length() > chIndx) {
1004 if (str.charAt(chIndx) == '=') {
1006 token = TT_DIVIDEBY;
1014 token = TT_MULTIPLY;
1015 if (str.length() > chIndx) {
1016 if (str.charAt(chIndx) == '*') {
1022 if (str.charAt(chIndx) == '=') {
1033 if (str.length() > chIndx) {
1034 if (str.charAt(chIndx) == '+') {
1036 token = TT_INCREMENT;
1040 if (str.charAt(chIndx) == '=') {
1049 token = TT_SUBTRACT;
1050 if (str.length() > chIndx) {
1051 if (str.charAt(chIndx) == '-') {
1053 token = TT_DECREMENT;
1057 if (str.charAt(chIndx) == '=') {
1059 token = TT_SUBTRACTFROM;
1063 if (str.charAt(chIndx) == '>') {
1075 if (str.length() > chIndx) {
1076 ch = str.charAt(chIndx);
1081 if (str.length() > chIndx) {
1082 ch = str.charAt(chIndx);
1086 token = TT_EX_EQUAL;
1103 if (str.length() > chIndx) {
1104 if (str.charAt(chIndx) == '=') {
1107 if (str.length() > chIndx) {
1108 ch = str.charAt(chIndx);
1112 token = TT_EX_UNEQUAL;
1123 if (str.length() > chIndx) {
1124 if (str.charAt(chIndx) == '=') {
1126 token = TT_GREATEREQUAL;
1129 if (str.charAt(chIndx) == '>') {
1132 if (str.length() > chIndx) {
1133 if (str.charAt(chIndx) == '=') {
1135 token = TT_RSHIFTASSIGN;
1147 if (str.length() > chIndx) {
1148 if (str.charAt(chIndx) == '=') {
1150 token = TT_LESSEQUAL;
1154 if (str.charAt(chIndx) == '<') {
1157 if (str.charAt(chIndx) == '<') {
1159 int startRow = rowCount;
1160 if (str.length() > chIndx) {
1162 ch = str.charAt(++chIndx);
1163 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1166 token = TT_STRING_CONSTANT;
1167 while (str.length() > chIndx) {
1168 ch = str.charAt(chIndx++);
1170 if (str.length() >= chIndx + identifier.length()) {
1171 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1172 chIndx += identifier.length();
1180 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1181 } else if (str.charAt(chIndx) == '=') {
1183 token = TT_LSHIFTASSIGN;
1195 if (str.length() > chIndx) {
1196 if (str.charAt(chIndx) == '|') {
1206 token = TT_AMPERSAND;
1207 if (str.length() > chIndx) {
1208 if (str.charAt(chIndx) == '&') {
1213 if (str.charAt(chIndx) == '=') {
1215 token = TT_ANDASSIGN;
1224 if (str.length() > chIndx) {
1225 if (str.charAt(chIndx) == ':') {
1240 throwSyntaxError("unexpected character: '" + ch + "'");
1243 if (token == TT_UNDEFINED) {
1244 throwSyntaxError("token not found");
1251 } catch (StringIndexOutOfBoundsException e) {
1252 // catched from charAt
1255 chIndx = str.length() + 1;
1260 // if (phpList != null) {
1261 // if (currentPHPString < phpList.size()) {
1262 // token = TT_UNDEFINED;
1263 // temp = (PHPString) phpList.get(currentPHPString++);
1264 // this.str = temp.getPHPString();
1265 // this.token = TT_EOF;
1267 // this.rowCount = temp.getLineNumber();
1268 // this.columnCount = 0;
1272 // token = TT_UNDEFINED;
1279 private void getIdentifier() {
1280 StringBuffer ident = new StringBuffer();
1285 // attention recursive call:
1287 token = TT_VARIABLE;
1290 token = TT_IDENTIFIER;
1294 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1298 identifier = ident.toString();
1301 // determine if this identitfer is a keyword
1302 // @todo improve this in future version
1303 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1305 token = i.intValue();
1309 private void getNumber() {
1310 StringBuffer inum = new StringBuffer();
1319 // determine number conversions:
1320 if (firstCh == '0') {
1349 if (numFormat == 16) {
1350 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1355 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1356 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1357 if (ch == '.' && dFlag != ' ') {
1360 if ((dFlag == 'E') || (dFlag == 'e')) {
1366 if ((ch == '-') || (ch == '+')) {
1380 doubleNumber = new Double(inum.toString());
1381 token = TT_DOUBLE_NUMBER;
1384 longNumber = Long.valueOf(inum.toString(), numFormat);
1385 token = TT_INT_NUMBER;
1389 } catch (Throwable e) {
1390 throwSyntaxError("Number format error: " + inum.toString());
1396 * @param openChar the opening char ('\'', '"', '`')
1397 * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
1398 * @param errorMsg the error message in case of parse error in the string
1400 private void getString(final char openChar, final int typeString, final String errorMsg) {
1401 StringBuffer sBuffer = new StringBuffer();
1402 boolean openString = true;
1403 int startRow = rowCount;
1404 while (str.length() > chIndx) {
1405 ch = str.charAt(chIndx++);
1408 if (str.length() > chIndx) {
1409 ch = str.charAt(chIndx++);
1412 } else if (ch == openChar) {
1415 } else if (ch == '\n') {
1417 columnCount = chIndx;
1423 if (typeString == TT_STRING_CONSTANT) {
1424 throwSyntaxError(errorMsg, startRow);
1426 throwSyntaxError(errorMsg);
1430 stringValue = sBuffer.toString();
1433 public void htmlParserTester(String input) {
1435 int startLineNumber = 1;
1439 boolean phpMode = false;
1440 boolean phpFound = false;
1442 phpList = new ArrayList();
1443 currentPHPString = 0;
1447 while (i < input.length()) {
1448 ch = input.charAt(i++);
1452 if ((!phpMode) && ch == '<') {
1453 ch2 = input.charAt(i++);
1455 ch2 = input.charAt(i++);
1456 if (Character.isWhitespace(ch2)) {
1461 startLineNumber = lineNumber;
1463 } else if (ch2 == 'p') {
1464 ch2 = input.charAt(i++);
1466 ch2 = input.charAt(i++);
1471 startLineNumber = lineNumber;
1477 } else if (ch2 == 'P') {
1478 ch2 = input.charAt(i++);
1480 ch2 = input.charAt(i++);
1485 startLineNumber = lineNumber;
1498 if (ch == '/' && i < input.length()) {
1499 ch2 = input.charAt(i++);
1501 while (i < input.length()) {
1502 ch = input.charAt(i++);
1503 if (ch == '?' && i < input.length()) {
1504 ch2 = input.charAt(i++);
1508 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1512 } else if (ch == '\n') {
1518 } else if (ch2 == '*') {
1519 // multi-line comment
1520 while (i < input.length()) {
1521 ch = input.charAt(i++);
1524 } else if (ch == '*' && i < input.length()) {
1525 ch2 = input.charAt(i++);
1536 } else if (ch == '#') {
1537 while (i < input.length()) {
1538 ch = input.charAt(i++);
1539 if (ch == '?' && i < input.length()) {
1540 ch2 = input.charAt(i++);
1544 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1548 } else if (ch == '\n') {
1554 } else if (ch == '"') {
1556 while (i < input.length()) {
1557 ch = input.charAt(i++);
1560 } else if (ch == '\\' && i < input.length()) { // escape
1562 } else if (ch == '"') {
1567 } else if (ch == '\'') {
1569 while (i < input.length()) {
1570 ch = input.charAt(i++);
1573 } else if (ch == '\\' && i < input.length()) { // escape
1575 } else if (ch == '\'') {
1582 if (ch == '?' && i < input.length()) {
1583 ch2 = input.charAt(i++);
1587 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1596 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1599 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1600 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1602 // for (int j=0;j<phpList.size();j++) {
1603 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1604 // int startIndx = temp.length()-10;
1605 // if (startIndx<0) {
1608 // System.out.println(temp.substring(startIndx)+"?>");
1610 phpParserTester(null, 1);
1612 // for(int j=0;j<phpList.size();j++) {
1613 // temp = (PHPString) phpList.get(j);
1614 // parser.start(temp.getPHPString(), temp.getLineNumber());
1617 } catch (CoreException e) {
1621 public void phpParserTester(String s, int rowCount) throws CoreException {
1624 if (phpList.size() != 0) {
1625 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1628 this.token = TT_EOF;
1630 this.rowCount = rowCount;
1631 this.columnCount = 0;
1632 this.phpEnd = false;
1633 this.phpMode = true;
1637 if (token != TT_EOF && token != TT_UNDEFINED) {
1640 if (token != TT_EOF && token != TT_UNDEFINED) {
1641 if (token == TT_ARGCLOSE) {
1642 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1644 if (token == TT_LISTCLOSE) {
1645 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1647 if (token == TT_PARTCLOSE) {
1648 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1651 if (token == TT_ARGOPEN) {
1652 throwSyntaxError("Read character '('; end-of-file not reached.");
1654 if (token == TT_LISTOPEN) {
1655 throwSyntaxError("Read character '{'; end-of-file not reached.");
1657 if (token == TT_PARTOPEN) {
1658 throwSyntaxError("Read character '['; end-of-file not reached.");
1661 throwSyntaxError("End-of-file not reached.");
1664 } catch (SyntaxError err) {
1668 setMarker(err.getMessage(), err.getLine(), ERROR);
1670 // if an error occured,
1671 // try to find keywords 'class' or 'function'
1672 // to parse the rest of the string
1673 while (token != TT_EOF && token != TT_UNDEFINED) {
1674 if (token == TT_class || token == TT_function) {
1679 if (token == TT_EOF || token == TT_UNDEFINED) {
1688 * Parses a string with php tags
1689 * i.e. '<body> <?php phpinfo() ?> </body>'
1691 public void parse(String s) throws CoreException {
1693 this.token = TT_EOF;
1696 this.columnCount = 0;
1697 this.phpEnd = false;
1698 this.phpMode = false;
1702 if (token != TT_EOF && token != TT_UNDEFINED) {
1705 if (token != TT_EOF && token != TT_UNDEFINED) {
1706 if (token == TT_ARGCLOSE) {
1707 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1709 if (token == TT_LISTCLOSE) {
1710 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1712 if (token == TT_PARTCLOSE) {
1713 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1716 if (token == TT_ARGOPEN) {
1717 throwSyntaxError("Read character '('; end-of-file not reached.");
1719 if (token == TT_LISTOPEN) {
1720 throwSyntaxError("Read character '{'; end-of-file not reached.");
1722 if (token == TT_PARTOPEN) {
1723 throwSyntaxError("Read character '['; end-of-file not reached.");
1726 throwSyntaxError("End-of-file not reached.");
1729 } catch (SyntaxError sytaxErr1) {
1730 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1732 // if an error occured,
1733 // try to find keywords 'class' or 'function'
1734 // to parse the rest of the string
1735 while (token != TT_EOF && token != TT_UNDEFINED) {
1736 if (token == TT_class || token == TT_function) {
1741 if (token == TT_EOF || token == TT_UNDEFINED) {
1744 } catch (SyntaxError sytaxErr2) {
1745 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1753 public PHPOutlineInfo parseInfo(Object parent, String s) {
1754 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1755 // Stack stack = new Stack();
1756 // stack.push(outlineInfo.getDeclarations());
1759 this.token = TT_EOF;
1762 this.columnCount = 0;
1763 this.phpEnd = false;
1764 this.phpMode = false;
1768 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1769 } catch (CoreException e) {
1774 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
1775 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1776 PHPSegmentWithChildren temp;
1778 String oldIdentifier;
1779 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1781 while (token != TT_EOF && token != TT_UNDEFINED) {
1782 if (token == TT_VARIABLE) {
1783 outlineInfo.addVariable(identifier);
1785 } else if (token == TT_var) {
1787 if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1789 outlineInfo.addVariable(identifier);
1790 if (token != TT_SEMICOLON) {
1791 oldIdentifier = identifier;
1794 case TT_VARIABLE : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1796 case TT_IDENTIFIER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1798 case TT_DOUBLE_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
1800 case TT_INT_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
1802 case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1804 case TT_STRING_CONSTANT : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1806 default : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
1810 current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1813 } else if (token == TT_function) {
1815 if (token == TT_AMPERSAND) {
1818 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1819 outlineInfo.addVariable(identifier);
1820 temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
1823 parseDeclarations(outlineInfo, temp, true);
1825 } else if (token == TT_class) {
1827 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
1828 outlineInfo.addVariable(identifier);
1829 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1831 // stack.push(temp);
1834 //skip tokens for classname, extends and others until we have the opening '{'
1835 while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1838 parseDeclarations(outlineInfo, temp, true);
1841 } else if (token == TT_LISTOPEN) {
1844 } else if (token == TT_LISTCLOSE) {
1847 if (counter == 0 && goBack) {
1850 } else if (token == TT_require || token == TT_require_once || token == TT_include || token == TT_include_once) {
1852 outlineInfo.addVariable(identifier);
1853 current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
1859 } catch (CoreException e) {
1860 } catch (SyntaxError sytaxErr) {
1862 setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
1863 } catch (CoreException e) {
1868 private void statementList() throws CoreException {
1871 if ((token == TT_LISTCLOSE)
1872 || (token == TT_case)
1873 || (token == TT_default)
1874 || (token == TT_elseif)
1875 || (token == TT_endif)
1876 || (token == TT_endfor)
1877 || (token == TT_endforeach)
1878 || (token == TT_endwhile)
1879 || (token == TT_endswitch)
1880 || (token == TT_EOF)
1881 || (token == TT_UNDEFINED)) {
1887 private void compoundStatement() throws CoreException {
1888 // '{' [statement-list] '}'
1889 if (token == TT_LISTOPEN) {
1892 throwSyntaxError("'{' expected in compound-statement.");
1894 if (token != TT_LISTCLOSE) {
1897 if (token == TT_LISTCLOSE) {
1900 throwSyntaxError("'}' expected in compound-statement.");
1904 private void statement() throws CoreException {
1905 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1906 String keyword = identifier;
1907 if (token == TT_include || token == TT_include_once) {
1910 if (token == TT_SEMICOLON) {
1914 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1919 } else if (token == TT_require || token == TT_require_once) {
1923 if (token == TT_SEMICOLON) {
1927 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1932 } else if (token == TT_if) {
1934 if (token == TT_ARGOPEN) {
1937 throwSyntaxError("'(' expected after 'if' keyword.");
1940 if (token == TT_ARGCLOSE) {
1943 throwSyntaxError("')' expected after 'if' condition.");
1948 } else if (token == TT_switch) {
1950 if (token == TT_ARGOPEN) {
1953 throwSyntaxError("'(' expected after 'switch' keyword.");
1956 if (token == TT_ARGCLOSE) {
1959 throwSyntaxError("')' expected after 'switch' condition.");
1963 } else if (token == TT_for) {
1965 if (token == TT_ARGOPEN) {
1968 throwSyntaxError("'(' expected after 'for' keyword.");
1970 if (token == TT_SEMICOLON) {
1974 if (token == TT_SEMICOLON) {
1977 throwSyntaxError("';' expected after 'for'.");
1980 if (token == TT_SEMICOLON) {
1984 if (token == TT_SEMICOLON) {
1987 throwSyntaxError("';' expected after 'for'.");
1990 if (token == TT_ARGCLOSE) {
1994 if (token == TT_ARGCLOSE) {
1997 throwSyntaxError("')' expected after 'for'.");
2002 } else if (token == TT_while) {
2004 if (token == TT_ARGOPEN) {
2007 throwSyntaxError("'(' expected after 'while' keyword.");
2010 if (token == TT_ARGCLOSE) {
2013 throwSyntaxError("')' expected after 'while' condition.");
2017 } else if (token == TT_do) {
2019 if (token == TT_LISTOPEN) {
2022 throwSyntaxError("'{' expected after 'do' keyword.");
2024 if (token != TT_LISTCLOSE) {
2027 if (token == TT_LISTCLOSE) {
2030 throwSyntaxError("'}' expected after 'do' keyword.");
2032 if (token == TT_while) {
2034 if (token == TT_ARGOPEN) {
2037 throwSyntaxError("'(' expected after 'while' keyword.");
2040 if (token == TT_ARGCLOSE) {
2043 throwSyntaxError("')' expected after 'while' condition.");
2046 throwSyntaxError("'while' expected after 'do' keyword.");
2048 if (token == TT_SEMICOLON) {
2052 throwSyntaxError("';' expected after do-while statement.");
2057 } else if (token == TT_foreach) {
2059 if (token == TT_ARGOPEN) {
2062 throwSyntaxError("'(' expected after 'foreach' keyword.");
2065 if (token == TT_as) {
2068 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2071 if (token == TT_FOREACH) {
2075 if (token == TT_ARGCLOSE) {
2078 throwSyntaxError("')' expected after 'foreach' expression.");
2083 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2085 if (token != TT_SEMICOLON) {
2088 if (token == TT_SEMICOLON) {
2092 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2098 } else if (token == TT_echo) {
2101 if (token == TT_SEMICOLON) {
2105 throwSyntaxError("';' expected after 'echo' statement.");
2110 // } else if (token == TT_print) {
2113 // if (token == TT_SEMICOLON) {
2117 // throwSyntaxError("';' expected after 'print' statement.");
2123 } else if (token == TT_global || token == TT_static) {
2126 if (token == TT_SEMICOLON) {
2130 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2136 // } else if (token == TT_unset) {
2138 // if (token == TT_ARGOPEN) {
2141 // throwSyntaxError("'(' expected after 'unset' keyword.");
2144 // if (token == TT_ARGCLOSE) {
2147 // throwSyntaxError("')' expected after 'unset' statement.");
2149 // if (token == TT_SEMICOLON) {
2153 // throwSyntaxError("';' expected after 'unset' statement.");
2159 // } else if (token == TT_exit || token == TT_die) {
2161 // if (token != TT_SEMICOLON) {
2164 // if (token == TT_SEMICOLON) {
2168 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2174 } else if (token == TT_define) {
2176 if (token == TT_ARGOPEN) {
2179 throwSyntaxError("'(' expected after 'define' keyword.");
2182 if (token == TT_COMMA) {
2185 throwSyntaxError("',' expected after first 'define' constant.");
2188 if (token == TT_COMMA) {
2192 if (token == TT_ARGCLOSE) {
2195 throwSyntaxError("')' expected after 'define' statement.");
2197 if (token == TT_SEMICOLON) {
2201 throwSyntaxError("';' expected after 'define' statement.");
2206 } else if (token == TT_function) {
2208 functionDefinition();
2210 } else if (token == TT_class) {
2216 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2217 } else if (token == TT_LISTOPEN) {
2218 // compoundStatement
2220 if (token != TT_LISTCLOSE) {
2223 if (token == TT_LISTCLOSE) {
2227 throwSyntaxError("'}' expected.");
2230 if (token != TT_SEMICOLON) {
2233 if (token == TT_SEMICOLON) {
2238 throwSyntaxError("';' expected after expression.");
2245 private void classDeclarator() throws CoreException {
2247 //identifier 'extends' identifier
2248 if (token == TT_IDENTIFIER) {
2250 if (token == TT_extends) {
2252 if (token == TT_IDENTIFIER) {
2255 throwSyntaxError("Class name expected after keyword 'extends'.");
2259 throwSyntaxError("Class name expected after keyword 'class'.");
2263 private void classBody() throws CoreException {
2264 //'{' [class-element-list] '}'
2265 if (token == TT_LISTOPEN) {
2267 if (token != TT_LISTCLOSE) {
2270 if (token == TT_LISTCLOSE) {
2273 throwSyntaxError("'}' expected at end of class body.");
2276 throwSyntaxError("'{' expected at start of class body.");
2280 private void classElementList() throws CoreException {
2283 } while (token == TT_function || token == TT_var);
2286 private void classElement() throws CoreException {
2288 //function-definition
2289 if (token == TT_function) {
2291 functionDefinition();
2292 } else if (token == TT_var) {
2296 throwSyntaxError("'function' or 'var' expected.");
2300 private void classProperty() throws CoreException {
2301 //'var' variable ';'
2302 //'var' variable '=' constant ';'
2304 if (token == TT_VARIABLE) {
2306 if (token == TT_ASSIGN) {
2311 throwSyntaxError("Variable expected after keyword 'var'.");
2313 if (token != TT_COMMA) {
2318 if (token == TT_SEMICOLON) {
2321 throwSyntaxError("';' expected after variable declaration.");
2325 private void functionDefinition() throws CoreException {
2326 functionDeclarator();
2327 compoundStatement();
2330 private void functionDeclarator() throws CoreException {
2331 //identifier '(' [parameter-list] ')'
2332 if (token == TT_AMPERSAND) {
2335 if (token == TT_IDENTIFIER) {
2337 if (token == TT_ARGOPEN) {
2340 throwSyntaxError("'(' expected in function declaration.");
2342 if (token != TT_ARGCLOSE) {
2345 if (token != TT_ARGCLOSE) {
2346 throwSyntaxError("')' expected in function declaration.");
2353 private void parameterList() throws CoreException {
2354 //parameter-declaration
2355 //parameter-list ',' parameter-declaration
2357 parameterDeclaration();
2358 if (token != TT_COMMA) {
2365 private void parameterDeclaration() throws CoreException {
2367 //variable-reference
2368 if (token == TT_AMPERSAND) {
2370 if (token == TT_VARIABLE) {
2373 throwSyntaxError("Variable expected after reference operator '&'.");
2376 //variable '=' constant
2377 if (token == TT_VARIABLE) {
2379 if (token == TT_ASSIGN) {
2387 private void labeledStatementList() throws CoreException {
2388 if (token != TT_case && token != TT_default) {
2389 throwSyntaxError("'case' or 'default' expected.");
2392 if (token == TT_case) {
2395 if (token == TT_DDOT) {
2397 if (token == TT_case || token == TT_default) { // empty case statement ?
2401 } else if (token == TT_SEMICOLON) {
2402 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2404 if (token == TT_case) { // empty case statement ?
2409 throwSyntaxError("':' character after 'case' constant expected.");
2411 } else { // TT_default
2413 if (token == TT_DDOT) {
2417 throwSyntaxError("':' character after 'default' expected.");
2420 } while (token == TT_case || token == TT_default);
2423 // public void labeledStatement() {
2424 // if (token == TT_case) {
2427 // if (token == TT_DDOT) {
2431 // throwSyntaxError("':' character after 'case' constant expected.");
2434 // } else if (token == TT_default) {
2436 // if (token == TT_DDOT) {
2440 // throwSyntaxError("':' character after 'default' expected.");
2446 // public void expressionStatement() {
2449 // private void inclusionStatement() {
2452 // public void compoundStatement() {
2455 // public void selectionStatement() {
2458 // public void iterationStatement() {
2461 // public void jumpStatement() {
2464 // public void outputStatement() {
2467 // public void scopeStatement() {
2470 // public void flowStatement() {
2473 // public void definitionStatement() {
2476 private void ifStatement() throws CoreException {
2477 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2478 if (token == TT_DDOT) {
2484 if (token == TT_DDOT) {
2488 if (token == TT_if) { //'else if'
2490 elseifStatementList();
2492 throwSyntaxError("':' expected after 'else'.");
2498 elseifStatementList();
2502 if (token != TT_endif) {
2503 throwSyntaxError("'endif' expected.");
2506 if (token != TT_SEMICOLON) {
2507 throwSyntaxError("';' expected after if-statement.");
2511 // statement [else-statement]
2513 if (token == TT_elseif) {
2515 if (token == TT_ARGOPEN) {
2518 throwSyntaxError("'(' expected after 'elseif' keyword.");
2521 if (token == TT_ARGCLOSE) {
2524 throwSyntaxError("')' expected after 'elseif' condition.");
2527 } else if (token == TT_else) {
2534 private void elseifStatementList() throws CoreException {
2540 if (token == TT_DDOT) {
2545 if (token == TT_if) { //'else if'
2548 throwSyntaxError("':' expected after 'else'.");
2561 private void elseifStatement() throws CoreException {
2562 if (token == TT_ARGOPEN) {
2565 if (token != TT_ARGOPEN) {
2566 throwSyntaxError("')' expected in else-if-statement.");
2569 if (token != TT_DDOT) {
2570 throwSyntaxError("':' expected in else-if-statement.");
2577 private void switchStatement() throws CoreException {
2578 if (token == TT_DDOT) {
2579 // ':' [labeled-statement-list] 'endswitch' ';'
2581 labeledStatementList();
2582 if (token != TT_endswitch) {
2583 throwSyntaxError("'endswitch' expected.");
2586 if (token != TT_SEMICOLON) {
2587 throwSyntaxError("';' expected after switch-statement.");
2591 // '{' [labeled-statement-list] '}'
2592 if (token != TT_LISTOPEN) {
2593 throwSyntaxError("'{' expected in switch statement.");
2596 if (token != TT_LISTCLOSE) {
2597 labeledStatementList();
2599 if (token != TT_LISTCLOSE) {
2600 throwSyntaxError("'}' expected in switch statement.");
2607 private void forStatement() throws CoreException {
2608 if (token == TT_DDOT) {
2611 if (token != TT_endfor) {
2612 throwSyntaxError("'endfor' expected.");
2615 if (token != TT_SEMICOLON) {
2616 throwSyntaxError("';' expected after for-statement.");
2624 private void whileStatement() throws CoreException {
2625 // ':' statement-list 'endwhile' ';'
2626 if (token == TT_DDOT) {
2629 if (token != TT_endwhile) {
2630 throwSyntaxError("'endwhile' expected.");
2633 if (token != TT_SEMICOLON) {
2634 throwSyntaxError("';' expected after while-statement.");
2642 private void foreachStatement() throws CoreException {
2643 if (token == TT_DDOT) {
2646 if (token != TT_endforeach) {
2647 throwSyntaxError("'endforeach' expected.");
2650 if (token != TT_SEMICOLON) {
2651 throwSyntaxError("';' expected after foreach-statement.");
2659 private void exitStatus() throws CoreException {
2660 if (token == TT_ARGOPEN) {
2663 throwSyntaxError("'(' expected in 'exit-status'.");
2665 if (token != TT_ARGCLOSE) {
2668 if (token == TT_ARGCLOSE) {
2671 throwSyntaxError("')' expected after 'exit-status'.");
2675 private void expressionList() throws CoreException {
2678 if (token == TT_COMMA) {
2686 private void expression() throws CoreException {
2687 //todo: find a better way to get the expression
2688 expression = new StringBuffer();
2689 for (int i = chIndx;i<str.length();i++) {
2690 if (str.charAt(i) == ';') {
2693 expression.append(str.charAt(i));
2695 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2698 logicalinclusiveorExpression();
2699 // while (token != TT_SEMICOLON) {
2705 private void postfixExpression() throws CoreException {
2707 boolean castFlag = false;
2722 case TT_STRING_CONSTANT :
2725 case TT_INTERPOLATED_STRING :
2730 if (token == TT_IDENTIFIER) {
2731 // check if identifier is a type:
2733 String str = identifier.toLowerCase();
2734 for (int i = 0; i < PHP_TYPES.length; i++) {
2735 if (PHP_TYPES[i].equals(str)) {
2742 if (token != TT_ARGCLOSE) {
2743 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2753 if (token != TT_ARGCLOSE) {
2754 throwSyntaxError(") expected in postfix-expression.");
2758 case TT_DOUBLE_NUMBER :
2761 case TT_INT_NUMBER :
2764 case TT_DOLLAROPEN :
2767 if (token != TT_LISTCLOSE) {
2768 throwSyntaxError("'}' expected after indirect variable token '${'.");
2775 if (token == TT_LISTOPEN) {
2778 if (token != TT_LISTCLOSE) {
2779 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2782 } else if (token == TT_ARGOPEN) {
2784 if (token != TT_ARGCLOSE) {
2786 if (token != TT_ARGCLOSE) {
2787 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2793 case TT_IDENTIFIER :
2796 if (token == TT_ARGOPEN) {
2798 if (token != TT_ARGCLOSE) {
2800 if (token != TT_ARGCLOSE) {
2801 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2810 // if (token == TT_SEMICOLON) {
2814 // throwSyntaxError("';' expected after 'print' statement.");
2821 if (token == TT_ARGOPEN) {
2823 if (token == TT_COMMA) {
2827 if (token != TT_ARGCLOSE) {
2828 throwSyntaxError("')' expected after 'list' keyword.");
2831 // if (token == TT_SET) {
2833 // logicalinclusiveorExpression();
2836 throwSyntaxError("'(' expected after 'list' keyword.");
2841 // if (token != TT_SEMICOLON) {
2844 // if (token == TT_SEMICOLON) {
2848 // throwSyntaxError("';' expected after 'exit' expression.");
2855 // if (token != TT_SEMICOLON) {
2858 // if (token == TT_SEMICOLON) {
2862 // throwSyntaxError("';' expected after 'die' expression.");
2869 // if (token == TT_ARGOPEN) {
2871 // if (token == TT_COMMA) {
2874 // expressionList();
2875 // if (token != TT_ARGCLOSE) {
2876 // throwSyntaxError("')' expected after 'list' keyword.");
2879 // if (token == TT_SET) {
2881 // logicalinclusiveorExpression();
2884 // throwSyntaxError("'(' expected after 'list' keyword.");
2888 boolean while_flag = true;
2894 if (token != TT_PARTCLOSE) {
2895 throwSyntaxError("] expected in postfix-expression.");
2899 case TT_DDOT2 : // ::
2902 if (token > TT_KEYWORD) {
2904 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2910 // if (token == TT_ARGOPEN) {
2912 // expressionList();
2913 // if (token != TT_ARGCLOSE) {
2914 // throwSyntaxError(") expected after variable '" + ident + "'.");
2919 case TT_IDENTIFIER :
2926 if (token != TT_LISTCLOSE) {
2927 throwSyntaxError("} expected in postfix-expression.");
2932 throwSyntaxError("Syntax error after '->' token.");
2933 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2934 if (token == TT_PARTOPEN) {
2937 if (token != TT_PARTCLOSE) {
2938 throwSyntaxError("] expected after '->'.");
2942 if (token == TT_ARGOPEN) {
2945 if (token != TT_ARGCLOSE) {
2946 throwSyntaxError(") expected after '->'.");
2950 if (token == TT_LISTOPEN) {
2953 if (token != TT_LISTCLOSE) {
2954 throwSyntaxError("} expected after '->'.");
2974 private void unaryExpression() throws CoreException {
2984 // '@' '&' '*' '+' '-' '~' '!'
3014 postfixExpression();
3018 private void castExpression() throws CoreException {
3019 // if (token == TT_ARGOPEN) {
3022 // if (token != TT_ARGCLOSE) {
3023 // throwSyntaxError(") expected after cast-expression.");
3030 private void typeName() throws CoreException {
3031 //'string' 'unset' 'array' 'object'
3033 //'real' 'double' 'float'
3036 if (token == TT_IDENTIFIER) {
3038 String str = identifier.toLowerCase();
3040 for (int i = 0; i < PHP_TYPES.length; i++) {
3041 if (PHP_TYPES[i].equals(str)) {
3046 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3049 private void assignExpression() throws CoreException {
3051 if (token == TT_ASSIGN) { // =
3053 logicalinclusiveorExpression();
3054 } else if (token == TT_DOTASSIGN) { // .=
3056 logicalinclusiveorExpression();
3057 } else if (token == TT_FOREACH) { // =>
3059 logicalinclusiveorExpression();
3060 } else if (token == TT_ADDTO) { // +=
3062 logicalinclusiveorExpression();
3063 } else if (token == TT_SUBTRACTFROM) { // -=
3065 logicalinclusiveorExpression();
3066 } else if (token == TT_TIMESBY) { // *=
3068 logicalinclusiveorExpression();
3069 } else if (token == TT_DIVIDEBY) { // *=
3071 logicalinclusiveorExpression();
3072 } else if (token == TT_MODASSIGN) { // %=
3074 logicalinclusiveorExpression();
3075 } else if (token == TT_ANDASSIGN) { // &=
3077 logicalinclusiveorExpression();
3078 } else if (token == TT_POWASSIGN) { // ^=
3080 logicalinclusiveorExpression();
3081 } else if (token == TT_LSHIFTASSIGN) { // <<=
3083 logicalinclusiveorExpression();
3084 } else if (token == TT_RSHIFTASSIGN) { // >>=
3086 logicalinclusiveorExpression();
3087 } else if (token == TT_TILDEASSIGN) { // ~=
3089 logicalinclusiveorExpression();
3093 private void multiplicativeExpression() throws CoreException {
3096 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3103 private void concatenationExpression() throws CoreException {
3105 multiplicativeExpression();
3106 if (token != TT_DOT) {
3113 private void additiveExpression() throws CoreException {
3115 concatenationExpression();
3116 if (token != TT_ADD && token != TT_SUBTRACT) {
3123 private void shiftExpression() throws CoreException {
3125 additiveExpression();
3126 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3133 private void relationalExpression() throws CoreException {
3136 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3143 private void identicalExpression() throws CoreException {
3145 relationalExpression();
3146 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3153 private void equalityExpression() throws CoreException {
3155 identicalExpression();
3156 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3163 private void ternaryExpression() throws CoreException {
3164 equalityExpression();
3165 if (token == TT_QUESTIONMARK) {
3168 if (token == TT_DDOT) {
3172 throwSyntaxError("':' expected in ternary operator '? :'.");
3177 private void andExpression() throws CoreException {
3179 ternaryExpression();
3180 if (token != TT_AMPERSAND) {
3187 private void exclusiveorExpression() throws CoreException {
3190 if (token != TT_POW) {
3197 private void inclusiveorExpression() throws CoreException {
3199 exclusiveorExpression();
3200 if (token != TT_LINE) {
3207 private void booleanandExpression() throws CoreException {
3209 inclusiveorExpression();
3210 if (token != TT_AND) {
3217 private void booleanorExpression() throws CoreException {
3219 booleanandExpression();
3220 if (token != TT_OR) {
3227 private void logicalandExpression() throws CoreException {
3229 booleanorExpression();
3230 if (token != TT_and) {
3237 private void logicalexclusiveorExpression() throws CoreException {
3239 logicalandExpression();
3240 if (token != TT_xor) {
3247 private void logicalinclusiveorExpression() throws CoreException {
3249 logicalexclusiveorExpression();
3250 if (token != TT_or) {
3257 // public void assignmentExpression() {
3258 // if (token == TT_VARIABLE) {
3260 // if (token == TT_SET) {
3262 // logicalinclusiveorExpression();
3265 // logicalinclusiveorExpression();
3269 private void variableList() throws CoreException {
3272 if (token == TT_COMMA) {
3280 private void variable() throws CoreException {
3281 if (token == TT_DOLLAROPEN) {
3285 if (token != TT_LISTCLOSE) {
3286 throwSyntaxError("'}' expected after indirect variable token '${'.");
3290 if (token == TT_VARIABLE) {
3292 if (token == TT_PARTOPEN) {
3295 if (token != TT_PARTCLOSE) {
3296 throwSyntaxError("']' expected in variable-list.");
3299 } else if (token == TT_ASSIGN) {
3304 throwSyntaxError("$-variable expected in variable-list.");
3309 private void constant() throws CoreException {
3315 case TT_DOUBLE_NUMBER :
3318 case TT_INT_NUMBER :
3322 throwSyntaxError("Constant expected after '+' presign.");
3328 case TT_DOUBLE_NUMBER :
3331 case TT_INT_NUMBER :
3335 throwSyntaxError("Constant expected after '-' presign.");
3347 case TT_IDENTIFIER :
3350 if (token == TT_ARGOPEN) {
3352 if (token != TT_ARGCLOSE) {
3354 if (token != TT_ARGCLOSE) {
3355 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3361 case TT_STRING_CONSTANT :
3364 case TT_INTERPOLATED_STRING :
3367 case TT_DOUBLE_NUMBER :
3370 case TT_INT_NUMBER :
3374 throwSyntaxError("Constant expected.");
3379 * Call the php parse command ( php -l -f <filename> )
3380 * and create markers according to the external parser output
3382 public static void phpExternalParse(IFile file) {
3383 //IFile file = (IFile) resource;
3384 IPath path = file.getFullPath();
3385 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3386 String filename = file.getLocation().toString();
3388 String[] arguments = { filename };
3389 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3390 String command = form.format(arguments);
3392 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3395 // parse the buffer to find the errors and warnings
3396 createMarkers(parserResult, file);
3397 } catch (CoreException e) {
3402 * Create markers according to the external parser output
3404 private static void createMarkers(String output, IFile file) throws CoreException {
3405 // delete all markers
3406 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3410 boolean flag = true;
3411 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3412 // newer php error output (tested with 4.2.3)
3413 scanLine(output, file, indx, brIndx);
3418 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3419 // older php error output (tested with 4.2.3)
3420 scanLine(output, file, indx, brIndx);
3426 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3428 String outLineNumberString;
3429 StringBuffer lineNumberBuffer = new StringBuffer(10);
3431 current = output.substring(indx, brIndx);
3433 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3434 int onLine = current.indexOf("on line <b>");
3436 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3437 for (int i = onLine; i < current.length(); i++) {
3438 ch = current.charAt(i);
3439 if ('0' <= ch && '9' >= ch) {
3440 lineNumberBuffer.append(ch);
3444 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3446 Hashtable attributes = new Hashtable();
3448 current = current.replaceAll("\n", "");
3449 current = current.replaceAll("<b>", "");
3450 current = current.replaceAll("</b>", "");
3451 MarkerUtilities.setMessage(attributes, current);
3453 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3454 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3455 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3456 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3458 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3459 MarkerUtilities.setLineNumber(attributes, lineNumber);
3460 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);