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;
17 import java.util.Stack;
19 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
20 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
21 import net.sourceforge.phpeclipse.phpeditor.PHPString;
22 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
23 import org.eclipse.core.resources.IFile;
24 import org.eclipse.core.resources.IMarker;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IPath;
27 import org.eclipse.jface.preference.IPreferenceStore;
28 import org.eclipse.ui.texteditor.MarkerUtilities;
30 public class PHPParser extends PHPKeywords {
31 // strings for external parser call
32 private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
33 private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
35 public static final int ERROR = 2;
36 public static final int WARNING = 1;
37 public static final int INFO = 0;
38 private IFile fileToParse;
39 private ArrayList phpList;
41 private int currentPHPString;
42 private boolean phpEnd;
44 private static HashMap keywordMap = null;
52 // row counter for syntax errors:
54 // column counter for syntax errors:
64 private boolean phpMode;
66 final static int TT_EOF = 0;
67 final static int TT_UNDEFINED = 1;
68 final static int TT_HTML = 2;
70 final static int TT_MOD = 30;
71 final static int TT_NOT = 31;
72 final static int TT_DOT = 32;
73 final static int TT_POW = 33;
74 final static int TT_DIV = 34;
75 final static int TT_MULTIPLY = 35;
76 final static int TT_SUBTRACT = 36;
77 final static int TT_ADD = 37;
78 final static int TT_EQUAL = 38;
79 final static int TT_UNEQUAL = 39;
80 final static int TT_GREATER = 40;
81 final static int TT_GREATEREQUAL = 41;
82 final static int TT_LESS = 42;
83 final static int TT_LESSEQUAL = 43;
84 final static int TT_AND = 44;
85 final static int TT_OR = 45;
86 final static int TT_HASH = 46;
87 final static int TT_DDOT = 47;
88 final static int TT_DOTASSIGN = 48;
90 final static int TT_ASSIGN = 49;
91 final static int TT_REF = 50;
92 final static int TT_FOREACH = 51;
93 final static int TT_AMPERSAND = 52;
94 final static int TT_DOLLARLISTOPEN = 53;
95 final static int TT_TILDE = 54;
96 final static int TT_TILDEASSIGN = 55;
97 final static int TT_MODASSIGN = 56;
98 final static int TT_POWASSIGN = 57;
99 final static int TT_RSHIFTASSIGN = 58;
100 final static int TT_LSHIFTASSIGN = 59;
101 final static int TT_ANDASSIGN = 60;
102 final static int TT_QUESTIONMARK = 61;
103 final static int TT_DDOT2 = 62;
104 final static int TT_AT = 63;
105 // final static int TT_HEREDOC = 64;
107 final static int TT_DOLLAROPEN = 127;
108 final static int TT_ARGOPEN = 128;
109 final static int TT_ARGCLOSE = 129;
110 final static int TT_LISTOPEN = 130;
111 final static int TT_LISTCLOSE = 131;
112 final static int TT_PARTOPEN = 132;
113 final static int TT_PARTCLOSE = 133;
114 final static int TT_COMMA = 134;
116 final static int TT_STRING = 136;
117 final static int TT_IDENTIFIER = 138;
118 final static int TT_DIGIT = 139;
119 final static int TT_SEMICOLON = 140;
120 final static int TT_SLOT = 141;
121 final static int TT_SLOTSEQUENCE = 142;
122 final static int TT_DECREMENT = 144;
123 final static int TT_INCREMENT = 145;
124 final static int TT_ADDTO = 146;
125 final static int TT_DIVIDEBY = 147;
126 final static int TT_SUBTRACTFROM = 148;
127 final static int TT_TIMESBY = 149;
128 final static int TT_VARIABLE = 150;
129 final static int TT_INT_NUMBER = 151;
130 final static int TT_DOUBLE_NUMBER = 152;
131 final static int TT_INTERPOLATED_STRING = 153;
132 final static int TT_STRING_CONSTANT = 154;
134 final static int TT_LSHIFT = 155;
135 final static int TT_RSHIFT = 156;
136 final static int TT_EX_EQUAL = 157;
137 final static int TT_EX_UNEQUAL = 158;
138 final static int TT_LINE = 159;
139 // final static int TT_AT = 153; // @
144 *@param sess Description of Parameter
147 public PHPParser(IFile fileToParse) {
148 if (keywordMap == null) {
149 keywordMap = new HashMap();
150 for (int i = 0; i < PHP_KEYWORS.length; i++) {
151 keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
154 this.currentPHPString = 0;
155 this.fileToParse = fileToParse;
161 this.columnCount = 0;
168 * Create marker for the parse error
170 private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
171 setMarker(fileToParse, message, lineNumber, errorLevel);
174 public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
176 Hashtable attributes = new Hashtable();
177 MarkerUtilities.setMessage(attributes, message);
178 switch (errorLevel) {
180 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
183 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
186 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
189 MarkerUtilities.setLineNumber(attributes, lineNumber);
190 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
194 private void throwSyntaxError(String error) {
196 if (str.length() < chIndx) {
199 // read until end-of-line
201 while (str.length() > eol) {
202 ch = str.charAt(eol++);
208 throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
211 private void throwSyntaxError(String error, int startRow) {
213 throw new SyntaxError(startRow, 0, " ", error);
217 * Method Declaration.
221 private void getChar() {
222 if (str.length() > chIndx) {
223 ch = str.charAt(chIndx++);
228 chIndx = str.length() + 1;
234 private void getNextToken_OldVersion() throws CoreException {
237 while (str.length() > chIndx) {
238 ch = str.charAt(chIndx++);
239 token = TT_UNDEFINED;
242 columnCount = chIndx;
243 continue; // while loop
245 if (str.length() == chIndx) {
248 if (!Character.isWhitespace(ch)) {
250 if (str.length() > chIndx) {
251 if (str.charAt(chIndx) == '{') {
253 token = TT_DOLLAROPEN;
260 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
264 if (ch >= '0' && ch <= '9') {
269 if (str.length() > chIndx) {
270 if (str.charAt(chIndx) == '/') {
272 // read comment until end of line:
273 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
277 } else if (str.charAt(chIndx) == '*') {
279 // multi line comment:
280 while (str.length() > chIndx) {
281 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
285 ch = str.charAt(chIndx++);
288 columnCount = chIndx;
294 } else if (ch == '#') {
295 // read comment until end of line:
296 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
300 } else if (ch == '"') {
301 // read string until end
302 boolean openString = true;
303 while (str.length() > chIndx) {
304 ch = str.charAt(chIndx++);
306 if (str.length() > chIndx) {
307 ch = str.charAt(chIndx++);
309 } else if (ch == '"') {
312 } else if (ch == '\n') {
314 columnCount = chIndx;
318 throwSyntaxError("Open string character '\"' at end of file.");
320 token = TT_INTERPOLATED_STRING;
322 } else if (ch == '\'') {
323 // read string until end
324 boolean openString = true;
325 int startRow = rowCount;
326 while (str.length() > chIndx) {
327 ch = str.charAt(chIndx++);
329 if (str.length() > chIndx) {
330 ch = str.charAt(chIndx++);
332 } else if (ch == '\'') {
335 } else if (ch == '\n') {
337 columnCount = chIndx;
341 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
343 token = TT_STRING_CONSTANT;
345 } else if (ch == '`') {
346 // read string until end
347 boolean openString = true;
348 int startRow = rowCount;
349 while (str.length() > chIndx) {
350 ch = str.charAt(chIndx++);
352 if (str.length() > chIndx) {
353 ch = str.charAt(chIndx++);
355 } else if (ch == '`') {
358 } else if (ch == '\n') {
360 columnCount = chIndx;
364 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
366 token = TT_STRING_CONSTANT;
385 token = TT_LISTCLOSE;
393 token = TT_PARTCLOSE;
401 token = TT_QUESTIONMARK;
408 if (str.length() > chIndx) {
409 if (str.charAt(chIndx) == '=') {
411 token = TT_TILDEASSIGN;
419 if (str.length() > chIndx) {
420 if (str.charAt(chIndx) == '=') {
422 token = TT_DOTASSIGN;
435 if (str.length() > chIndx) {
436 if (str.charAt(chIndx) == '=') {
438 token = TT_MODASSIGN;
445 token = TT_SEMICOLON;
450 if (str.length() > chIndx) {
451 if (str.charAt(chIndx) == '=') {
453 token = TT_POWASSIGN;
462 if (str.length() > chIndx) {
463 if (str.charAt(chIndx) == '=') {
474 if (str.length() > chIndx) {
475 if (str.charAt(chIndx) == '*') {
481 if (str.charAt(chIndx) == '=') {
492 if (str.length() > chIndx) {
493 if (str.charAt(chIndx) == '+') {
495 token = TT_INCREMENT;
499 if (str.charAt(chIndx) == '=') {
509 if (str.length() > chIndx) {
510 if (str.charAt(chIndx) == '-') {
512 token = TT_DECREMENT;
516 if (str.charAt(chIndx) == '=') {
518 token = TT_SUBTRACTFROM;
522 if (str.charAt(chIndx) == '>') {
534 if (str.length() > chIndx) {
535 ch = str.charAt(chIndx);
540 if (str.length() > chIndx) {
541 ch = str.charAt(chIndx);
562 if (str.length() > chIndx) {
563 if (str.charAt(chIndx) == '=') {
566 if (str.length() > chIndx) {
567 ch = str.charAt(chIndx);
571 token = TT_EX_UNEQUAL;
582 if (str.length() > chIndx) {
583 if (str.charAt(chIndx) == '=') {
585 token = TT_GREATEREQUAL;
588 if (str.charAt(chIndx) == '>') {
591 if (str.length() > chIndx) {
592 if (str.charAt(chIndx) == '=') {
594 token = TT_RSHIFTASSIGN;
606 if (str.length() > chIndx) {
607 if (str.charAt(chIndx) == '=') {
609 token = TT_LESSEQUAL;
613 if (str.charAt(chIndx) == '<') {
616 if (str.charAt(chIndx) == '<') {
618 int startRow = rowCount;
619 if (str.length() > chIndx) {
621 ch = str.charAt(++chIndx);
622 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
625 token = TT_STRING_CONSTANT;
626 while (str.length() > chIndx) {
627 ch = str.charAt(chIndx++);
629 if (str.length() >= chIndx + identifier.length()) {
630 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
631 chIndx += identifier.length();
639 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
640 } else if (str.charAt(chIndx) == '=') {
642 token = TT_LSHIFTASSIGN;
654 if (str.length() > chIndx) {
655 if (str.charAt(chIndx) == '|') {
665 token = TT_AMPERSAND;
666 if (str.length() > chIndx) {
667 if (str.charAt(chIndx) == '&') {
672 if (str.charAt(chIndx) == '=') {
674 token = TT_ANDASSIGN;
683 if (str.length() > chIndx) {
684 if (str.charAt(chIndx) == ':') {
699 throwSyntaxError("unexpected character: '" + ch + "'");
702 if (token == TT_UNDEFINED) {
703 throwSyntaxError("token not found");
710 chIndx = str.length() + 1;
715 if (phpList != null) {
716 if (currentPHPString < phpList.size()) {
717 token = TT_UNDEFINED;
718 temp = (PHPString) phpList.get(currentPHPString++);
719 this.str = temp.getPHPString();
722 this.rowCount = temp.getLineNumber();
723 this.columnCount = 0;
727 token = TT_UNDEFINED;
733 * gets the next token from input
735 private void getNextToken() throws CoreException {
736 boolean phpFound = false;
743 while (str.length() > chIndx) {
744 token = TT_UNDEFINED;
745 ch = str.charAt(chIndx++);
751 ch2 = str.charAt(chIndx++);
753 ch2 = str.charAt(chIndx++);
754 if (Character.isWhitespace(ch2)) {
759 } else if (ch2 == 'p') {
760 ch2 = str.charAt(chIndx++);
762 ch2 = str.charAt(chIndx++);
771 } else if (ch2 == 'P') {
772 ch2 = str.charAt(chIndx++);
774 ch2 = str.charAt(chIndx++);
793 while (str.length() > chIndx) {
794 ch = str.charAt(chIndx++);
795 token = TT_UNDEFINED;
798 columnCount = chIndx;
799 continue; // while loop
801 if (str.length() == chIndx) {
804 if (!Character.isWhitespace(ch)) {
806 if (str.length() > chIndx) {
807 if (str.charAt(chIndx) == '{') {
809 token = TT_DOLLAROPEN;
816 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
820 if (ch >= '0' && ch <= '9') {
825 if (str.length() > chIndx) {
826 if (str.charAt(chIndx) == '/') {
829 // read comment until end of line:
830 while ((str.length() > chIndx) && (ch != '\n')) {
831 ch = str.charAt(chIndx++);
833 ch2 = str.charAt(chIndx);
847 } else if (str.charAt(chIndx) == '*') {
849 // multi line comment:
850 while (str.length() > chIndx) {
851 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
855 ch = str.charAt(chIndx++);
858 columnCount = chIndx;
864 } else if (ch == '#') {
865 // read comment until end of line:
866 while ((str.length() > chIndx) && (ch != '\n')) {
867 ch = str.charAt(chIndx++);
869 ch2 = str.charAt(chIndx);
883 } else if (ch == '"') {
884 // read string until end
885 boolean openString = true;
886 while (str.length() > chIndx) {
887 ch = str.charAt(chIndx++);
889 if (str.length() > chIndx) {
890 ch = str.charAt(chIndx++);
892 } else if (ch == '"') {
895 } else if (ch == '\n') {
897 columnCount = chIndx;
901 throwSyntaxError("Open string character '\"' at end of file.");
903 token = TT_INTERPOLATED_STRING;
905 } else if (ch == '\'') {
906 // read string until end
907 boolean openString = true;
908 int startRow = rowCount;
909 while (str.length() > chIndx) {
910 ch = str.charAt(chIndx++);
912 if (str.length() > chIndx) {
913 ch = str.charAt(chIndx++);
915 } else if (ch == '\'') {
918 } else if (ch == '\n') {
920 columnCount = chIndx;
924 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
926 token = TT_STRING_CONSTANT;
928 } else if (ch == '`') {
929 // read string until end
930 boolean openString = true;
931 int startRow = rowCount;
932 while (str.length() > chIndx) {
933 ch = str.charAt(chIndx++);
935 if (str.length() > chIndx) {
936 ch = str.charAt(chIndx++);
938 } else if (ch == '`') {
941 } else if (ch == '\n') {
943 columnCount = chIndx;
947 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
949 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
950 token = TT_STRING_CONSTANT;
969 token = TT_LISTCLOSE;
977 token = TT_PARTCLOSE;
985 token = TT_QUESTIONMARK;
986 if (str.length() > chIndx) {
987 if (str.charAt(chIndx) == '>') {
1003 if (str.length() > chIndx) {
1004 if (str.charAt(chIndx) == '=') {
1006 token = TT_TILDEASSIGN;
1014 if (str.length() > chIndx) {
1015 if (str.charAt(chIndx) == '=') {
1017 token = TT_DOTASSIGN;
1030 if (str.length() > chIndx) {
1031 if (str.charAt(chIndx) == '=') {
1033 token = TT_MODASSIGN;
1040 token = TT_SEMICOLON;
1045 if (str.length() > chIndx) {
1046 if (str.charAt(chIndx) == '=') {
1048 token = TT_POWASSIGN;
1057 if (str.length() > chIndx) {
1058 if (str.charAt(chIndx) == '=') {
1060 token = TT_DIVIDEBY;
1068 token = TT_MULTIPLY;
1069 if (str.length() > chIndx) {
1070 if (str.charAt(chIndx) == '*') {
1076 if (str.charAt(chIndx) == '=') {
1087 if (str.length() > chIndx) {
1088 if (str.charAt(chIndx) == '+') {
1090 token = TT_INCREMENT;
1094 if (str.charAt(chIndx) == '=') {
1103 token = TT_SUBTRACT;
1104 if (str.length() > chIndx) {
1105 if (str.charAt(chIndx) == '-') {
1107 token = TT_DECREMENT;
1111 if (str.charAt(chIndx) == '=') {
1113 token = TT_SUBTRACTFROM;
1117 if (str.charAt(chIndx) == '>') {
1129 if (str.length() > chIndx) {
1130 ch = str.charAt(chIndx);
1135 if (str.length() > chIndx) {
1136 ch = str.charAt(chIndx);
1140 token = TT_EX_EQUAL;
1157 if (str.length() > chIndx) {
1158 if (str.charAt(chIndx) == '=') {
1161 if (str.length() > chIndx) {
1162 ch = str.charAt(chIndx);
1166 token = TT_EX_UNEQUAL;
1177 if (str.length() > chIndx) {
1178 if (str.charAt(chIndx) == '=') {
1180 token = TT_GREATEREQUAL;
1183 if (str.charAt(chIndx) == '>') {
1186 if (str.length() > chIndx) {
1187 if (str.charAt(chIndx) == '=') {
1189 token = TT_RSHIFTASSIGN;
1201 if (str.length() > chIndx) {
1202 if (str.charAt(chIndx) == '=') {
1204 token = TT_LESSEQUAL;
1208 if (str.charAt(chIndx) == '<') {
1211 if (str.charAt(chIndx) == '<') {
1213 int startRow = rowCount;
1214 if (str.length() > chIndx) {
1216 ch = str.charAt(++chIndx);
1217 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1220 token = TT_STRING_CONSTANT;
1221 while (str.length() > chIndx) {
1222 ch = str.charAt(chIndx++);
1224 if (str.length() >= chIndx + identifier.length()) {
1225 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1226 chIndx += identifier.length();
1234 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1235 } else if (str.charAt(chIndx) == '=') {
1237 token = TT_LSHIFTASSIGN;
1249 if (str.length() > chIndx) {
1250 if (str.charAt(chIndx) == '|') {
1260 token = TT_AMPERSAND;
1261 if (str.length() > chIndx) {
1262 if (str.charAt(chIndx) == '&') {
1267 if (str.charAt(chIndx) == '=') {
1269 token = TT_ANDASSIGN;
1278 if (str.length() > chIndx) {
1279 if (str.charAt(chIndx) == ':') {
1294 throwSyntaxError("unexpected character: '" + ch + "'");
1297 if (token == TT_UNDEFINED) {
1298 throwSyntaxError("token not found");
1305 } catch (StringIndexOutOfBoundsException e) {
1306 // catched from charAt
1309 chIndx = str.length() + 1;
1314 // if (phpList != null) {
1315 // if (currentPHPString < phpList.size()) {
1316 // token = TT_UNDEFINED;
1317 // temp = (PHPString) phpList.get(currentPHPString++);
1318 // this.str = temp.getPHPString();
1319 // this.token = TT_EOF;
1321 // this.rowCount = temp.getLineNumber();
1322 // this.columnCount = 0;
1326 // token = TT_UNDEFINED;
1332 private void getIdentifier() {
1333 StringBuffer ident = new StringBuffer();
1338 // attention recursive call:
1340 token = TT_VARIABLE;
1343 token = TT_IDENTIFIER;
1347 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1351 identifier = ident.toString();
1354 // determine if this identitfer is a keyword
1355 // @todo improve this in future version
1356 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1358 token = i.intValue();
1362 private void getNumber() {
1363 StringBuffer inum = new StringBuffer();
1372 // determine number conversions:
1373 if (firstCh == '0') {
1402 if (numFormat == 16) {
1403 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1408 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1409 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1410 if (ch == '.' && dFlag != ' ') {
1413 if ((dFlag == 'E') || (dFlag == 'e')) {
1419 if ((ch == '-') || (ch == '+')) {
1433 doubleNumber = new Double(inum.toString());
1434 token = TT_DOUBLE_NUMBER;
1437 longNumber = Long.valueOf(inum.toString(), numFormat);
1438 token = TT_INT_NUMBER;
1442 } catch (Throwable e) {
1443 throwSyntaxError("Number format error: " + inum.toString());
1447 public void htmlParserTester(String input) {
1449 int startLineNumber = 1;
1453 boolean phpMode = false;
1454 boolean phpFound = false;
1456 phpList = new ArrayList();
1457 currentPHPString = 0;
1461 while (i < input.length()) {
1462 ch = input.charAt(i++);
1466 if ((!phpMode) && ch == '<') {
1467 ch2 = input.charAt(i++);
1469 ch2 = input.charAt(i++);
1470 if (Character.isWhitespace(ch2)) {
1475 startLineNumber = lineNumber;
1477 } else if (ch2 == 'p') {
1478 ch2 = input.charAt(i++);
1480 ch2 = input.charAt(i++);
1485 startLineNumber = lineNumber;
1491 } else if (ch2 == 'P') {
1492 ch2 = input.charAt(i++);
1494 ch2 = input.charAt(i++);
1499 startLineNumber = lineNumber;
1512 if (ch == '/' && i < input.length()) {
1513 ch2 = input.charAt(i++);
1515 while (i < input.length()) {
1516 ch = input.charAt(i++);
1517 if (ch == '?' && i < input.length()) {
1518 ch2 = input.charAt(i++);
1522 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1526 } else if (ch == '\n') {
1532 } else if (ch2 == '*') {
1533 // multi-line comment
1534 while (i < input.length()) {
1535 ch = input.charAt(i++);
1538 } else if (ch == '*' && i < input.length()) {
1539 ch2 = input.charAt(i++);
1550 } else if (ch == '#') {
1551 while (i < input.length()) {
1552 ch = input.charAt(i++);
1553 if (ch == '?' && i < input.length()) {
1554 ch2 = input.charAt(i++);
1558 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1562 } else if (ch == '\n') {
1568 } else if (ch == '"') {
1570 while (i < input.length()) {
1571 ch = input.charAt(i++);
1574 } else if (ch == '\\' && i < input.length()) { // escape
1576 } else if (ch == '"') {
1581 } else if (ch == '\'') {
1583 while (i < input.length()) {
1584 ch = input.charAt(i++);
1587 } else if (ch == '\\' && i < input.length()) { // escape
1589 } else if (ch == '\'') {
1596 if (ch == '?' && i < input.length()) {
1597 ch2 = input.charAt(i++);
1601 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1610 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1613 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1614 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1616 // for (int j=0;j<phpList.size();j++) {
1617 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1618 // int startIndx = temp.length()-10;
1619 // if (startIndx<0) {
1622 // System.out.println(temp.substring(startIndx)+"?>");
1624 phpParserTester(null, 1);
1626 // for(int j=0;j<phpList.size();j++) {
1627 // temp = (PHPString) phpList.get(j);
1628 // parser.start(temp.getPHPString(), temp.getLineNumber());
1631 } catch (CoreException e) {
1635 public void phpParserTester(String s, int rowCount) throws CoreException {
1638 if (phpList.size() != 0) {
1639 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1642 this.token = TT_EOF;
1644 this.rowCount = rowCount;
1645 this.columnCount = 0;
1646 this.phpEnd = false;
1647 this.phpMode = true;
1651 if (token != TT_EOF && token != TT_UNDEFINED) {
1654 if (token != TT_EOF && token != TT_UNDEFINED) {
1655 if (token == TT_ARGCLOSE) {
1656 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1658 if (token == TT_LISTCLOSE) {
1659 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1661 if (token == TT_PARTCLOSE) {
1662 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1665 if (token == TT_ARGOPEN) {
1666 throwSyntaxError("Read character '('; end-of-file not reached.");
1668 if (token == TT_LISTOPEN) {
1669 throwSyntaxError("Read character '{'; end-of-file not reached.");
1671 if (token == TT_PARTOPEN) {
1672 throwSyntaxError("Read character '['; end-of-file not reached.");
1675 throwSyntaxError("End-of-file not reached.");
1678 } catch (SyntaxError err) {
1682 setMarker(err.getMessage(), err.getLine(), ERROR);
1684 // if an error occured,
1685 // try to find keywords 'class' or 'function'
1686 // to parse the rest of the string
1687 while (token != TT_EOF && token != TT_UNDEFINED) {
1688 if (token == TT_class || token == TT_function) {
1693 if (token == TT_EOF || token == TT_UNDEFINED) {
1702 * Parses a string with php tags
1703 * i.e. '<body> <?php phpinfo() ?> </body>'
1705 public void parse(String s) throws CoreException {
1707 this.token = TT_EOF;
1710 this.columnCount = 0;
1711 this.phpEnd = false;
1712 this.phpMode = false;
1716 if (token != TT_EOF && token != TT_UNDEFINED) {
1719 if (token != TT_EOF && token != TT_UNDEFINED) {
1720 if (token == TT_ARGCLOSE) {
1721 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1723 if (token == TT_LISTCLOSE) {
1724 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1726 if (token == TT_PARTCLOSE) {
1727 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1730 if (token == TT_ARGOPEN) {
1731 throwSyntaxError("Read character '('; end-of-file not reached.");
1733 if (token == TT_LISTOPEN) {
1734 throwSyntaxError("Read character '{'; end-of-file not reached.");
1736 if (token == TT_PARTOPEN) {
1737 throwSyntaxError("Read character '['; end-of-file not reached.");
1740 throwSyntaxError("End-of-file not reached.");
1743 } catch (SyntaxError sytaxErr1) {
1744 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1746 // if an error occured,
1747 // try to find keywords 'class' or 'function'
1748 // to parse the rest of the string
1749 while (token != TT_EOF && token != TT_UNDEFINED) {
1750 if (token == TT_class || token == TT_function) {
1755 if (token == TT_EOF || token == TT_UNDEFINED) {
1758 } catch (SyntaxError sytaxErr2) {
1759 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1767 public PHPOutlineInfo parseInfo(Object parent, String s) {
1768 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1769 // Stack stack = new Stack();
1770 // stack.push(outlineInfo.getDeclarations());
1773 this.token = TT_EOF;
1776 this.columnCount = 0;
1777 this.phpEnd = false;
1778 this.phpMode = false;
1782 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1783 } catch (CoreException e) {
1788 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPClassDeclaration current, boolean goBack) {
1789 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1790 PHPClassDeclaration temp;
1794 while (token != TT_EOF && token != TT_UNDEFINED) {
1795 if (token == TT_VARIABLE) {
1796 outlineInfo.addVariable(identifier);
1798 } else if (token == TT_function) {
1800 if (token == TT_AMPERSAND) {
1803 if (token == TT_IDENTIFIER) {
1804 outlineInfo.addVariable(identifier);
1805 current.add(new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length()));
1808 } else if (token == TT_class) {
1810 if (token == TT_IDENTIFIER) {
1811 outlineInfo.addVariable(identifier);
1812 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1814 // stack.push(temp);
1816 while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1819 parseDeclarations(outlineInfo, temp, true);
1822 } else if (token == TT_LISTOPEN) {
1825 } else if (token == TT_LISTCLOSE) {
1828 if (counter == 0 && goBack) {
1835 } catch (CoreException e) {
1839 private void statementList() throws CoreException {
1842 if ((token == TT_LISTCLOSE)
1843 || (token == TT_case)
1844 || (token == TT_default)
1845 || (token == TT_elseif)
1846 || (token == TT_endif)
1847 || (token == TT_endfor)
1848 || (token == TT_endforeach)
1849 || (token == TT_endwhile)
1850 || (token == TT_endswitch)
1851 || (token == TT_EOF)
1852 || (token == TT_UNDEFINED)) {
1858 private void compoundStatement() throws CoreException {
1859 // '{' [statement-list] '}'
1860 if (token == TT_LISTOPEN) {
1863 throwSyntaxError("'{' expected in compound-statement.");
1865 if (token != TT_LISTCLOSE) {
1868 if (token == TT_LISTCLOSE) {
1871 throwSyntaxError("'}' expected in compound-statement.");
1875 private void statement() throws CoreException {
1876 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1877 String keyword = identifier;
1878 if (token == TT_include || token == TT_include_once) {
1881 if (token == TT_SEMICOLON) {
1885 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1890 } else if (token == TT_require || token == TT_require_once) {
1894 if (token == TT_SEMICOLON) {
1898 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1903 } else if (token == TT_if) {
1905 if (token == TT_ARGOPEN) {
1908 throwSyntaxError("'(' expected after 'if' keyword.");
1911 if (token == TT_ARGCLOSE) {
1914 throwSyntaxError("')' expected after 'if' condition.");
1919 } else if (token == TT_switch) {
1921 if (token == TT_ARGOPEN) {
1924 throwSyntaxError("'(' expected after 'switch' keyword.");
1927 if (token == TT_ARGCLOSE) {
1930 throwSyntaxError("')' expected after 'switch' condition.");
1934 } else if (token == TT_for) {
1936 if (token == TT_ARGOPEN) {
1939 throwSyntaxError("'(' expected after 'for' keyword.");
1941 if (token == TT_SEMICOLON) {
1945 if (token == TT_SEMICOLON) {
1948 throwSyntaxError("';' expected after 'for'.");
1951 if (token == TT_SEMICOLON) {
1955 if (token == TT_SEMICOLON) {
1958 throwSyntaxError("';' expected after 'for'.");
1961 if (token == TT_ARGCLOSE) {
1965 if (token == TT_ARGCLOSE) {
1968 throwSyntaxError("')' expected after 'for'.");
1973 } else if (token == TT_while) {
1975 if (token == TT_ARGOPEN) {
1978 throwSyntaxError("'(' expected after 'while' keyword.");
1981 if (token == TT_ARGCLOSE) {
1984 throwSyntaxError("')' expected after 'while' condition.");
1988 } else if (token == TT_do) {
1990 if (token == TT_LISTOPEN) {
1993 throwSyntaxError("'{' expected after 'do' keyword.");
1995 if (token != TT_LISTCLOSE) {
1998 if (token == TT_LISTCLOSE) {
2001 throwSyntaxError("'}' expected after 'do' keyword.");
2003 if (token == TT_while) {
2005 if (token == TT_ARGOPEN) {
2008 throwSyntaxError("'(' expected after 'while' keyword.");
2011 if (token == TT_ARGCLOSE) {
2014 throwSyntaxError("')' expected after 'while' condition.");
2017 throwSyntaxError("'while' expected after 'do' keyword.");
2019 if (token == TT_SEMICOLON) {
2023 throwSyntaxError("';' expected after do-while statement.");
2028 } else if (token == TT_foreach) {
2030 if (token == TT_ARGOPEN) {
2033 throwSyntaxError("'(' expected after 'foreach' keyword.");
2036 if (token == TT_as) {
2039 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2042 if (token == TT_FOREACH) {
2046 if (token == TT_ARGCLOSE) {
2049 throwSyntaxError("')' expected after 'foreach' expression.");
2054 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2056 if (token != TT_SEMICOLON) {
2059 if (token == TT_SEMICOLON) {
2063 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2069 } else if (token == TT_echo) {
2072 if (token == TT_SEMICOLON) {
2076 throwSyntaxError("';' expected after 'echo' statement.");
2081 // } else if (token == TT_print) {
2084 // if (token == TT_SEMICOLON) {
2088 // throwSyntaxError("';' expected after 'print' statement.");
2094 } else if (token == TT_global || token == TT_static) {
2097 if (token == TT_SEMICOLON) {
2101 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2107 // } else if (token == TT_unset) {
2109 // if (token == TT_ARGOPEN) {
2112 // throwSyntaxError("'(' expected after 'unset' keyword.");
2115 // if (token == TT_ARGCLOSE) {
2118 // throwSyntaxError("')' expected after 'unset' statement.");
2120 // if (token == TT_SEMICOLON) {
2124 // throwSyntaxError("';' expected after 'unset' statement.");
2130 // } else if (token == TT_exit || token == TT_die) {
2132 // if (token != TT_SEMICOLON) {
2135 // if (token == TT_SEMICOLON) {
2139 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2145 } else if (token == TT_define) {
2147 if (token == TT_ARGOPEN) {
2150 throwSyntaxError("'(' expected after 'define' keyword.");
2153 if (token == TT_COMMA) {
2156 throwSyntaxError("',' expected after first 'define' constant.");
2159 if (token == TT_COMMA) {
2163 if (token == TT_ARGCLOSE) {
2166 throwSyntaxError("')' expected after 'define' statement.");
2168 if (token == TT_SEMICOLON) {
2172 throwSyntaxError("';' expected after 'define' statement.");
2177 } else if (token == TT_function) {
2179 functionDefinition();
2181 } else if (token == TT_class) {
2187 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2188 } else if (token == TT_LISTOPEN) {
2189 // compoundStatement
2191 if (token != TT_LISTCLOSE) {
2194 if (token == TT_LISTCLOSE) {
2198 throwSyntaxError("'}' expected.");
2201 if (token != TT_SEMICOLON) {
2204 if (token == TT_SEMICOLON) {
2209 throwSyntaxError("';' expected after expression.");
2216 private void classDeclarator() throws CoreException {
2218 //identifier 'extends' identifier
2219 if (token == TT_IDENTIFIER) {
2221 if (token == TT_extends) {
2223 if (token == TT_IDENTIFIER) {
2226 throwSyntaxError("Class name expected after keyword 'extends'.");
2230 throwSyntaxError("Class name expected after keyword 'class'.");
2234 private void classBody() throws CoreException {
2235 //'{' [class-element-list] '}'
2236 if (token == TT_LISTOPEN) {
2238 if (token != TT_LISTCLOSE) {
2241 if (token == TT_LISTCLOSE) {
2244 throwSyntaxError("'}' expected at end of class body.");
2247 throwSyntaxError("'{' expected at start of class body.");
2251 private void classElementList() throws CoreException {
2254 } while (token == TT_function || token == TT_var);
2257 private void classElement() throws CoreException {
2259 //function-definition
2260 if (token == TT_function) {
2262 functionDefinition();
2263 } else if (token == TT_var) {
2267 throwSyntaxError("'function' or 'var' expected.");
2271 private void classProperty() throws CoreException {
2272 //'var' variable ';'
2273 //'var' variable '=' constant ';'
2275 if (token == TT_VARIABLE) {
2277 if (token == TT_ASSIGN) {
2282 throwSyntaxError("Variable expected after keyword 'var'.");
2284 if (token != TT_COMMA) {
2289 if (token == TT_SEMICOLON) {
2292 throwSyntaxError("';' expected after variable declaration.");
2296 private void functionDefinition() throws CoreException {
2297 functionDeclarator();
2298 compoundStatement();
2301 private void functionDeclarator() throws CoreException {
2302 //identifier '(' [parameter-list] ')'
2303 if (token == TT_AMPERSAND) {
2306 if (token == TT_IDENTIFIER) {
2308 if (token == TT_ARGOPEN) {
2311 throwSyntaxError("'(' expected in function declaration.");
2313 if (token != TT_ARGCLOSE) {
2316 if (token != TT_ARGCLOSE) {
2317 throwSyntaxError("')' expected in function declaration.");
2324 private void parameterList() throws CoreException {
2325 //parameter-declaration
2326 //parameter-list ',' parameter-declaration
2328 parameterDeclaration();
2329 if (token != TT_COMMA) {
2336 private void parameterDeclaration() throws CoreException {
2338 //variable-reference
2339 if (token == TT_AMPERSAND) {
2341 if (token == TT_VARIABLE) {
2344 throwSyntaxError("Variable expected after reference operator '&'.");
2347 //variable '=' constant
2348 if (token == TT_VARIABLE) {
2350 if (token == TT_ASSIGN) {
2358 private void labeledStatementList() throws CoreException {
2359 if (token != TT_case && token != TT_default) {
2360 throwSyntaxError("'case' or 'default' expected.");
2363 if (token == TT_case) {
2366 if (token == TT_DDOT) {
2368 if (token == TT_case || token == TT_default) { // empty case statement ?
2372 } else if (token == TT_SEMICOLON) {
2373 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2375 if (token == TT_case) { // empty case statement ?
2380 throwSyntaxError("':' character after 'case' constant expected.");
2382 } else { // TT_default
2384 if (token == TT_DDOT) {
2388 throwSyntaxError("':' character after 'default' expected.");
2391 } while (token == TT_case || token == TT_default);
2394 // public void labeledStatement() {
2395 // if (token == TT_case) {
2398 // if (token == TT_DDOT) {
2402 // throwSyntaxError("':' character after 'case' constant expected.");
2405 // } else if (token == TT_default) {
2407 // if (token == TT_DDOT) {
2411 // throwSyntaxError("':' character after 'default' expected.");
2417 // public void expressionStatement() {
2420 // private void inclusionStatement() {
2423 // public void compoundStatement() {
2426 // public void selectionStatement() {
2429 // public void iterationStatement() {
2432 // public void jumpStatement() {
2435 // public void outputStatement() {
2438 // public void scopeStatement() {
2441 // public void flowStatement() {
2444 // public void definitionStatement() {
2447 private void ifStatement() throws CoreException {
2448 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2449 if (token == TT_DDOT) {
2455 if (token == TT_DDOT) {
2459 if (token == TT_if) { //'else if'
2461 elseifStatementList();
2463 throwSyntaxError("':' expected after 'else'.");
2469 elseifStatementList();
2473 if (token != TT_endif) {
2474 throwSyntaxError("'endif' expected.");
2477 if (token != TT_SEMICOLON) {
2478 throwSyntaxError("';' expected after if-statement.");
2482 // statement [else-statement]
2484 if (token == TT_elseif) {
2486 if (token == TT_ARGOPEN) {
2489 throwSyntaxError("'(' expected after 'elseif' keyword.");
2492 if (token == TT_ARGCLOSE) {
2495 throwSyntaxError("')' expected after 'elseif' condition.");
2498 } else if (token == TT_else) {
2505 private void elseifStatementList() throws CoreException {
2511 if (token == TT_DDOT) {
2516 if (token == TT_if) { //'else if'
2519 throwSyntaxError("':' expected after 'else'.");
2532 private void elseifStatement() throws CoreException {
2533 if (token == TT_ARGOPEN) {
2536 if (token != TT_ARGOPEN) {
2537 throwSyntaxError("')' expected in else-if-statement.");
2540 if (token != TT_DDOT) {
2541 throwSyntaxError("':' expected in else-if-statement.");
2548 private void switchStatement() throws CoreException {
2549 if (token == TT_DDOT) {
2550 // ':' [labeled-statement-list] 'endswitch' ';'
2552 labeledStatementList();
2553 if (token != TT_endswitch) {
2554 throwSyntaxError("'endswitch' expected.");
2557 if (token != TT_SEMICOLON) {
2558 throwSyntaxError("';' expected after switch-statement.");
2562 // '{' [labeled-statement-list] '}'
2563 if (token != TT_LISTOPEN) {
2564 throwSyntaxError("'{' expected in switch statement.");
2567 if (token != TT_LISTCLOSE) {
2568 labeledStatementList();
2570 if (token != TT_LISTCLOSE) {
2571 throwSyntaxError("'}' expected in switch statement.");
2578 private void forStatement() throws CoreException {
2579 if (token == TT_DDOT) {
2582 if (token != TT_endfor) {
2583 throwSyntaxError("'endfor' expected.");
2586 if (token != TT_SEMICOLON) {
2587 throwSyntaxError("';' expected after for-statement.");
2595 private void whileStatement() throws CoreException {
2596 // ':' statement-list 'endwhile' ';'
2597 if (token == TT_DDOT) {
2600 if (token != TT_endwhile) {
2601 throwSyntaxError("'endwhile' expected.");
2604 if (token != TT_SEMICOLON) {
2605 throwSyntaxError("';' expected after while-statement.");
2613 private void foreachStatement() throws CoreException {
2614 if (token == TT_DDOT) {
2617 if (token != TT_endforeach) {
2618 throwSyntaxError("'endforeach' expected.");
2621 if (token != TT_SEMICOLON) {
2622 throwSyntaxError("';' expected after foreach-statement.");
2630 private void exitStatus() throws CoreException {
2631 if (token == TT_ARGOPEN) {
2634 throwSyntaxError("'(' expected in 'exit-status'.");
2636 if (token != TT_ARGCLOSE) {
2639 if (token == TT_ARGCLOSE) {
2642 throwSyntaxError("')' expected after 'exit-status'.");
2646 private void expressionList() throws CoreException {
2649 if (token == TT_COMMA) {
2657 private void expression() throws CoreException {
2658 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2661 logicalinclusiveorExpression();
2662 // while (token != TT_SEMICOLON) {
2668 private void postfixExpression() throws CoreException {
2670 boolean castFlag = false;
2685 case TT_STRING_CONSTANT :
2688 case TT_INTERPOLATED_STRING :
2693 if (token == TT_IDENTIFIER) {
2694 // check if identifier is a type:
2696 String str = identifier.toLowerCase();
2697 for (int i = 0; i < PHP_TYPES.length; i++) {
2698 if (PHP_TYPES[i].equals(str)) {
2705 if (token != TT_ARGCLOSE) {
2706 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2716 if (token != TT_ARGCLOSE) {
2717 throwSyntaxError(") expected in postfix-expression.");
2721 case TT_DOUBLE_NUMBER :
2724 case TT_INT_NUMBER :
2727 case TT_DOLLAROPEN :
2730 if (token != TT_LISTCLOSE) {
2731 throwSyntaxError("'}' expected after indirect variable token '${'.");
2738 if (token == TT_LISTOPEN) {
2741 if (token != TT_LISTCLOSE) {
2742 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2745 } else if (token == TT_ARGOPEN) {
2747 if (token != TT_ARGCLOSE) {
2749 if (token != TT_ARGCLOSE) {
2750 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2756 case TT_IDENTIFIER :
2759 if (token == TT_ARGOPEN) {
2761 if (token != TT_ARGCLOSE) {
2763 if (token != TT_ARGCLOSE) {
2764 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2773 // if (token == TT_SEMICOLON) {
2777 // throwSyntaxError("';' expected after 'print' statement.");
2784 if (token == TT_ARGOPEN) {
2786 if (token == TT_COMMA) {
2790 if (token != TT_ARGCLOSE) {
2791 throwSyntaxError("')' expected after 'list' keyword.");
2794 // if (token == TT_SET) {
2796 // logicalinclusiveorExpression();
2799 throwSyntaxError("'(' expected after 'list' keyword.");
2804 // if (token != TT_SEMICOLON) {
2807 // if (token == TT_SEMICOLON) {
2811 // throwSyntaxError("';' expected after 'exit' expression.");
2818 // if (token != TT_SEMICOLON) {
2821 // if (token == TT_SEMICOLON) {
2825 // throwSyntaxError("';' expected after 'die' expression.");
2832 // if (token == TT_ARGOPEN) {
2834 // if (token == TT_COMMA) {
2837 // expressionList();
2838 // if (token != TT_ARGCLOSE) {
2839 // throwSyntaxError("')' expected after 'list' keyword.");
2842 // if (token == TT_SET) {
2844 // logicalinclusiveorExpression();
2847 // throwSyntaxError("'(' expected after 'list' keyword.");
2851 boolean while_flag = true;
2857 if (token != TT_PARTCLOSE) {
2858 throwSyntaxError("] expected in postfix-expression.");
2862 case TT_DDOT2 : // ::
2865 if (token > TT_KEYWORD) {
2867 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2873 // if (token == TT_ARGOPEN) {
2875 // expressionList();
2876 // if (token != TT_ARGCLOSE) {
2877 // throwSyntaxError(") expected after variable '" + ident + "'.");
2882 case TT_IDENTIFIER :
2889 if (token != TT_LISTCLOSE) {
2890 throwSyntaxError("} expected in postfix-expression.");
2895 throwSyntaxError("Syntax error after '->' token.");
2896 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2897 if (token == TT_PARTOPEN) {
2900 if (token != TT_PARTCLOSE) {
2901 throwSyntaxError("] expected after '->'.");
2905 if (token == TT_ARGOPEN) {
2908 if (token != TT_ARGCLOSE) {
2909 throwSyntaxError(") expected after '->'.");
2913 if (token == TT_LISTOPEN) {
2916 if (token != TT_LISTCLOSE) {
2917 throwSyntaxError("} expected after '->'.");
2937 private void unaryExpression() throws CoreException {
2947 // '@' '&' '*' '+' '-' '~' '!'
2977 postfixExpression();
2981 private void castExpression() throws CoreException {
2982 // if (token == TT_ARGOPEN) {
2985 // if (token != TT_ARGCLOSE) {
2986 // throwSyntaxError(") expected after cast-expression.");
2993 private void typeName() throws CoreException {
2994 //'string' 'unset' 'array' 'object'
2996 //'real' 'double' 'float'
2999 if (token == TT_IDENTIFIER) {
3001 String str = identifier.toLowerCase();
3003 for (int i = 0; i < PHP_TYPES.length; i++) {
3004 if (PHP_TYPES[i].equals(str)) {
3009 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3012 private void assignExpression() throws CoreException {
3014 if (token == TT_ASSIGN) { // =
3016 logicalinclusiveorExpression();
3017 } else if (token == TT_DOTASSIGN) { // .=
3019 logicalinclusiveorExpression();
3020 } else if (token == TT_FOREACH) { // =>
3022 logicalinclusiveorExpression();
3023 } else if (token == TT_ADDTO) { // +=
3025 logicalinclusiveorExpression();
3026 } else if (token == TT_SUBTRACTFROM) { // -=
3028 logicalinclusiveorExpression();
3029 } else if (token == TT_TIMESBY) { // *=
3031 logicalinclusiveorExpression();
3032 } else if (token == TT_DIVIDEBY) { // *=
3034 logicalinclusiveorExpression();
3035 } else if (token == TT_MODASSIGN) { // %=
3037 logicalinclusiveorExpression();
3038 } else if (token == TT_ANDASSIGN) { // &=
3040 logicalinclusiveorExpression();
3041 } else if (token == TT_POWASSIGN) { // ^=
3043 logicalinclusiveorExpression();
3044 } else if (token == TT_LSHIFTASSIGN) { // <<=
3046 logicalinclusiveorExpression();
3047 } else if (token == TT_RSHIFTASSIGN) { // >>=
3049 logicalinclusiveorExpression();
3050 } else if (token == TT_TILDEASSIGN) { // ~=
3052 logicalinclusiveorExpression();
3056 private void multiplicativeExpression() throws CoreException {
3059 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3066 private void concatenationExpression() throws CoreException {
3068 multiplicativeExpression();
3069 if (token != TT_DOT) {
3076 private void additiveExpression() throws CoreException {
3078 concatenationExpression();
3079 if (token != TT_ADD && token != TT_SUBTRACT) {
3086 private void shiftExpression() throws CoreException {
3088 additiveExpression();
3089 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3096 private void relationalExpression() throws CoreException {
3099 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3106 private void identicalExpression() throws CoreException {
3108 relationalExpression();
3109 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3116 private void equalityExpression() throws CoreException {
3118 identicalExpression();
3119 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3126 private void ternaryExpression() throws CoreException {
3127 equalityExpression();
3128 if (token == TT_QUESTIONMARK) {
3131 if (token == TT_DDOT) {
3135 throwSyntaxError("':' expected in ternary operator '? :'.");
3140 private void andExpression() throws CoreException {
3142 ternaryExpression();
3143 if (token != TT_AMPERSAND) {
3150 private void exclusiveorExpression() throws CoreException {
3153 if (token != TT_POW) {
3160 private void inclusiveorExpression() throws CoreException {
3162 exclusiveorExpression();
3163 if (token != TT_LINE) {
3170 private void booleanandExpression() throws CoreException {
3172 inclusiveorExpression();
3173 if (token != TT_AND) {
3180 private void booleanorExpression() throws CoreException {
3182 booleanandExpression();
3183 if (token != TT_OR) {
3190 private void logicalandExpression() throws CoreException {
3192 booleanorExpression();
3193 if (token != TT_and) {
3200 private void logicalexclusiveorExpression() throws CoreException {
3202 logicalandExpression();
3203 if (token != TT_xor) {
3210 private void logicalinclusiveorExpression() throws CoreException {
3212 logicalexclusiveorExpression();
3213 if (token != TT_or) {
3220 // public void assignmentExpression() {
3221 // if (token == TT_VARIABLE) {
3223 // if (token == TT_SET) {
3225 // logicalinclusiveorExpression();
3228 // logicalinclusiveorExpression();
3232 private void variableList() throws CoreException {
3235 if (token == TT_COMMA) {
3243 private void variable() throws CoreException {
3244 if (token == TT_DOLLAROPEN) {
3248 if (token != TT_LISTCLOSE) {
3249 throwSyntaxError("'}' expected after indirect variable token '${'.");
3253 if (token == TT_VARIABLE) {
3255 if (token == TT_PARTOPEN) {
3258 if (token != TT_PARTCLOSE) {
3259 throwSyntaxError("']' expected in variable-list.");
3262 } else if (token == TT_ASSIGN) {
3267 throwSyntaxError("$-variable expected in variable-list.");
3272 private void constant() throws CoreException {
3278 case TT_DOUBLE_NUMBER :
3281 case TT_INT_NUMBER :
3285 throwSyntaxError("Constant expected after '+' presign.");
3291 case TT_DOUBLE_NUMBER :
3294 case TT_INT_NUMBER :
3298 throwSyntaxError("Constant expected after '-' presign.");
3310 case TT_IDENTIFIER :
3313 if (token == TT_ARGOPEN) {
3315 if (token != TT_ARGCLOSE) {
3317 if (token != TT_ARGCLOSE) {
3318 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3324 case TT_STRING_CONSTANT :
3327 case TT_INTERPOLATED_STRING :
3330 case TT_DOUBLE_NUMBER :
3333 case TT_INT_NUMBER :
3337 throwSyntaxError("Constant expected.");
3342 * Call the php parse command ( php -l -f <filename> )
3343 * and create markers according to the external parser output
3345 public static void phpExternalParse(IFile file) {
3346 //IFile file = (IFile) resource;
3347 IPath path = file.getFullPath();
3348 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3349 String filename = file.getLocation().toString();
3351 String[] arguments = { filename };
3352 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3353 String command = form.format(arguments);
3355 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3358 // parse the buffer to find the errors and warnings
3359 createMarkers(parserResult, file);
3360 } catch (CoreException e) {
3365 * Create markers according to the external parser output
3367 private static void createMarkers(String output, IFile file) throws CoreException {
3368 // delete all markers
3369 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3373 boolean flag = true;
3374 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3375 // newer php error output (tested with 4.2.3)
3376 scanLine(output, file, indx, brIndx);
3381 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3382 // older php error output (tested with 4.2.3)
3383 scanLine(output, file, indx, brIndx);
3389 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3391 String outLineNumberString;
3392 StringBuffer lineNumberBuffer = new StringBuffer(10);
3394 current = output.substring(indx, brIndx);
3396 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3397 int onLine = current.indexOf("on line <b>");
3399 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3400 for (int i = onLine; i < current.length(); i++) {
3401 ch = current.charAt(i);
3402 if ('0' <= ch && '9' >= ch) {
3403 lineNumberBuffer.append(ch);
3407 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3409 Hashtable attributes = new Hashtable();
3411 current = current.replaceAll("\n", "");
3412 current = current.replaceAll("<b>", "");
3413 current = current.replaceAll("</b>", "");
3414 MarkerUtilities.setMessage(attributes, current);
3416 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3417 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3418 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3419 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3421 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3422 MarkerUtilities.setLineNumber(attributes, lineNumber);
3423 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);