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 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
367 token = TT_STRING_CONSTANT;
386 token = TT_LISTCLOSE;
394 token = TT_PARTCLOSE;
402 token = TT_QUESTIONMARK;
409 if (str.length() > chIndx) {
410 if (str.charAt(chIndx) == '=') {
412 token = TT_TILDEASSIGN;
420 if (str.length() > chIndx) {
421 if (str.charAt(chIndx) == '=') {
423 token = TT_DOTASSIGN;
436 if (str.length() > chIndx) {
437 if (str.charAt(chIndx) == '=') {
439 token = TT_MODASSIGN;
446 token = TT_SEMICOLON;
451 if (str.length() > chIndx) {
452 if (str.charAt(chIndx) == '=') {
454 token = TT_POWASSIGN;
463 if (str.length() > chIndx) {
464 if (str.charAt(chIndx) == '=') {
475 if (str.length() > chIndx) {
476 if (str.charAt(chIndx) == '*') {
482 if (str.charAt(chIndx) == '=') {
493 if (str.length() > chIndx) {
494 if (str.charAt(chIndx) == '+') {
496 token = TT_INCREMENT;
500 if (str.charAt(chIndx) == '=') {
510 if (str.length() > chIndx) {
511 if (str.charAt(chIndx) == '-') {
513 token = TT_DECREMENT;
517 if (str.charAt(chIndx) == '=') {
519 token = TT_SUBTRACTFROM;
523 if (str.charAt(chIndx) == '>') {
535 if (str.length() > chIndx) {
536 ch = str.charAt(chIndx);
541 if (str.length() > chIndx) {
542 ch = str.charAt(chIndx);
563 if (str.length() > chIndx) {
564 if (str.charAt(chIndx) == '=') {
567 if (str.length() > chIndx) {
568 ch = str.charAt(chIndx);
572 token = TT_EX_UNEQUAL;
583 if (str.length() > chIndx) {
584 if (str.charAt(chIndx) == '=') {
586 token = TT_GREATEREQUAL;
589 if (str.charAt(chIndx) == '>') {
592 if (str.length() > chIndx) {
593 if (str.charAt(chIndx) == '=') {
595 token = TT_RSHIFTASSIGN;
607 if (str.length() > chIndx) {
608 if (str.charAt(chIndx) == '=') {
610 token = TT_LESSEQUAL;
614 if (str.charAt(chIndx) == '<') {
617 if (str.charAt(chIndx) == '<') {
619 int startRow = rowCount;
620 if (str.length() > chIndx) {
622 ch = str.charAt(++chIndx);
623 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
626 token = TT_STRING_CONSTANT;
627 while (str.length() > chIndx) {
628 ch = str.charAt(chIndx++);
630 if (str.length() >= chIndx + identifier.length()) {
631 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
632 chIndx += identifier.length();
640 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
641 } else if (str.charAt(chIndx) == '=') {
643 token = TT_LSHIFTASSIGN;
655 if (str.length() > chIndx) {
656 if (str.charAt(chIndx) == '|') {
666 token = TT_AMPERSAND;
667 if (str.length() > chIndx) {
668 if (str.charAt(chIndx) == '&') {
673 if (str.charAt(chIndx) == '=') {
675 token = TT_ANDASSIGN;
684 if (str.length() > chIndx) {
685 if (str.charAt(chIndx) == ':') {
700 throwSyntaxError("unexpected character: '" + ch + "'");
703 if (token == TT_UNDEFINED) {
704 throwSyntaxError("token not found");
711 chIndx = str.length() + 1;
716 if (phpList != null) {
717 if (currentPHPString < phpList.size()) {
718 token = TT_UNDEFINED;
719 temp = (PHPString) phpList.get(currentPHPString++);
720 this.str = temp.getPHPString();
723 this.rowCount = temp.getLineNumber();
724 this.columnCount = 0;
728 token = TT_UNDEFINED;
734 * gets the next token from input
736 private void getNextToken() throws CoreException {
737 boolean phpFound = false;
744 while (str.length() > chIndx) {
745 token = TT_UNDEFINED;
746 ch = str.charAt(chIndx++);
752 ch2 = str.charAt(chIndx++);
754 ch2 = str.charAt(chIndx++);
755 if (Character.isWhitespace(ch2)) {
760 } else if (ch2 == 'p') {
761 ch2 = str.charAt(chIndx++);
763 ch2 = str.charAt(chIndx++);
772 } else if (ch2 == 'P') {
773 ch2 = str.charAt(chIndx++);
775 ch2 = str.charAt(chIndx++);
794 while (str.length() > chIndx) {
795 ch = str.charAt(chIndx++);
796 token = TT_UNDEFINED;
799 columnCount = chIndx;
800 continue; // while loop
802 if (str.length() == chIndx) {
805 if (!Character.isWhitespace(ch)) {
807 if (str.length() > chIndx) {
808 if (str.charAt(chIndx) == '{') {
810 token = TT_DOLLAROPEN;
817 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
821 if (ch >= '0' && ch <= '9') {
826 if (str.length() > chIndx) {
827 if (str.charAt(chIndx) == '/') {
830 // read comment until end of line:
831 while ((str.length() > chIndx) && (ch != '\n')) {
832 ch = str.charAt(chIndx++);
834 ch2 = str.charAt(chIndx);
848 } else if (str.charAt(chIndx) == '*') {
850 // multi line comment:
851 while (str.length() > chIndx) {
852 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
856 ch = str.charAt(chIndx++);
859 columnCount = chIndx;
865 } else if (ch == '#') {
866 // read comment until end of line:
867 while ((str.length() > chIndx) && (ch != '\n')) {
868 ch = str.charAt(chIndx++);
870 ch2 = str.charAt(chIndx);
884 } else if (ch == '"') {
885 // read string until end
886 boolean openString = true;
887 while (str.length() > chIndx) {
888 ch = str.charAt(chIndx++);
890 if (str.length() > chIndx) {
891 ch = str.charAt(chIndx++);
893 } else if (ch == '"') {
896 } else if (ch == '\n') {
898 columnCount = chIndx;
902 throwSyntaxError("Open string character '\"' at end of file.");
904 token = TT_INTERPOLATED_STRING;
906 } else if (ch == '\'') {
907 // read string until end
908 boolean openString = true;
909 int startRow = rowCount;
910 while (str.length() > chIndx) {
911 ch = str.charAt(chIndx++);
913 if (str.length() > chIndx) {
914 ch = str.charAt(chIndx++);
916 } else if (ch == '\'') {
919 } else if (ch == '\n') {
921 columnCount = chIndx;
925 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
927 token = TT_STRING_CONSTANT;
929 } else if (ch == '`') {
930 // read string until end
931 boolean openString = true;
932 int startRow = rowCount;
933 while (str.length() > chIndx) {
934 ch = str.charAt(chIndx++);
936 if (str.length() > chIndx) {
937 ch = str.charAt(chIndx++);
939 } else if (ch == '`') {
942 } else if (ch == '\n') {
944 columnCount = chIndx;
948 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
950 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
951 token = TT_STRING_CONSTANT;
970 token = TT_LISTCLOSE;
978 token = TT_PARTCLOSE;
986 token = TT_QUESTIONMARK;
987 if (str.length() > chIndx) {
988 if (str.charAt(chIndx) == '>') {
1004 if (str.length() > chIndx) {
1005 if (str.charAt(chIndx) == '=') {
1007 token = TT_TILDEASSIGN;
1015 if (str.length() > chIndx) {
1016 if (str.charAt(chIndx) == '=') {
1018 token = TT_DOTASSIGN;
1031 if (str.length() > chIndx) {
1032 if (str.charAt(chIndx) == '=') {
1034 token = TT_MODASSIGN;
1041 token = TT_SEMICOLON;
1046 if (str.length() > chIndx) {
1047 if (str.charAt(chIndx) == '=') {
1049 token = TT_POWASSIGN;
1058 if (str.length() > chIndx) {
1059 if (str.charAt(chIndx) == '=') {
1061 token = TT_DIVIDEBY;
1069 token = TT_MULTIPLY;
1070 if (str.length() > chIndx) {
1071 if (str.charAt(chIndx) == '*') {
1077 if (str.charAt(chIndx) == '=') {
1088 if (str.length() > chIndx) {
1089 if (str.charAt(chIndx) == '+') {
1091 token = TT_INCREMENT;
1095 if (str.charAt(chIndx) == '=') {
1104 token = TT_SUBTRACT;
1105 if (str.length() > chIndx) {
1106 if (str.charAt(chIndx) == '-') {
1108 token = TT_DECREMENT;
1112 if (str.charAt(chIndx) == '=') {
1114 token = TT_SUBTRACTFROM;
1118 if (str.charAt(chIndx) == '>') {
1130 if (str.length() > chIndx) {
1131 ch = str.charAt(chIndx);
1136 if (str.length() > chIndx) {
1137 ch = str.charAt(chIndx);
1141 token = TT_EX_EQUAL;
1158 if (str.length() > chIndx) {
1159 if (str.charAt(chIndx) == '=') {
1162 if (str.length() > chIndx) {
1163 ch = str.charAt(chIndx);
1167 token = TT_EX_UNEQUAL;
1178 if (str.length() > chIndx) {
1179 if (str.charAt(chIndx) == '=') {
1181 token = TT_GREATEREQUAL;
1184 if (str.charAt(chIndx) == '>') {
1187 if (str.length() > chIndx) {
1188 if (str.charAt(chIndx) == '=') {
1190 token = TT_RSHIFTASSIGN;
1202 if (str.length() > chIndx) {
1203 if (str.charAt(chIndx) == '=') {
1205 token = TT_LESSEQUAL;
1209 if (str.charAt(chIndx) == '<') {
1212 if (str.charAt(chIndx) == '<') {
1214 int startRow = rowCount;
1215 if (str.length() > chIndx) {
1217 ch = str.charAt(++chIndx);
1218 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1221 token = TT_STRING_CONSTANT;
1222 while (str.length() > chIndx) {
1223 ch = str.charAt(chIndx++);
1225 if (str.length() >= chIndx + identifier.length()) {
1226 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1227 chIndx += identifier.length();
1235 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1236 } else if (str.charAt(chIndx) == '=') {
1238 token = TT_LSHIFTASSIGN;
1250 if (str.length() > chIndx) {
1251 if (str.charAt(chIndx) == '|') {
1261 token = TT_AMPERSAND;
1262 if (str.length() > chIndx) {
1263 if (str.charAt(chIndx) == '&') {
1268 if (str.charAt(chIndx) == '=') {
1270 token = TT_ANDASSIGN;
1279 if (str.length() > chIndx) {
1280 if (str.charAt(chIndx) == ':') {
1295 throwSyntaxError("unexpected character: '" + ch + "'");
1298 if (token == TT_UNDEFINED) {
1299 throwSyntaxError("token not found");
1306 } catch (StringIndexOutOfBoundsException e) {
1307 // catched from charAt
1310 chIndx = str.length() + 1;
1315 // if (phpList != null) {
1316 // if (currentPHPString < phpList.size()) {
1317 // token = TT_UNDEFINED;
1318 // temp = (PHPString) phpList.get(currentPHPString++);
1319 // this.str = temp.getPHPString();
1320 // this.token = TT_EOF;
1322 // this.rowCount = temp.getLineNumber();
1323 // this.columnCount = 0;
1327 // token = TT_UNDEFINED;
1333 private void getIdentifier() {
1334 StringBuffer ident = new StringBuffer();
1338 token = TT_VARIABLE;
1340 token = TT_IDENTIFIER;
1343 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1347 identifier = ident.toString();
1350 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1352 token = i.intValue();
1356 private void getNumber() {
1357 StringBuffer inum = new StringBuffer();
1366 // determine number conversions:
1367 if (firstCh == '0') {
1396 if (numFormat == 16) {
1397 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1402 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1403 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1404 if (ch == '.' && dFlag != ' ') {
1407 if ((dFlag == 'E') || (dFlag == 'e')) {
1413 if ((ch == '-') || (ch == '+')) {
1427 doubleNumber = new Double(inum.toString());
1428 token = TT_DOUBLE_NUMBER;
1431 longNumber = Long.valueOf(inum.toString(), numFormat);
1432 token = TT_INT_NUMBER;
1436 } catch (Throwable e) {
1437 throwSyntaxError("Number format error: " + inum.toString());
1441 public void htmlParserTester(String input) {
1443 int startLineNumber = 1;
1447 boolean phpMode = false;
1448 boolean phpFound = false;
1450 phpList = new ArrayList();
1451 currentPHPString = 0;
1455 while (i < input.length()) {
1456 ch = input.charAt(i++);
1460 if ((!phpMode) && ch == '<') {
1461 ch2 = input.charAt(i++);
1463 ch2 = input.charAt(i++);
1464 if (Character.isWhitespace(ch2)) {
1469 startLineNumber = lineNumber;
1471 } else if (ch2 == 'p') {
1472 ch2 = input.charAt(i++);
1474 ch2 = input.charAt(i++);
1479 startLineNumber = lineNumber;
1485 } else if (ch2 == 'P') {
1486 ch2 = input.charAt(i++);
1488 ch2 = input.charAt(i++);
1493 startLineNumber = lineNumber;
1506 if (ch == '/' && i < input.length()) {
1507 ch2 = input.charAt(i++);
1509 while (i < input.length()) {
1510 ch = input.charAt(i++);
1511 if (ch == '?' && i < input.length()) {
1512 ch2 = input.charAt(i++);
1516 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1520 } else if (ch == '\n') {
1526 } else if (ch2 == '*') {
1527 // multi-line comment
1528 while (i < input.length()) {
1529 ch = input.charAt(i++);
1532 } else if (ch == '*' && i < input.length()) {
1533 ch2 = input.charAt(i++);
1544 } else if (ch == '#') {
1545 while (i < input.length()) {
1546 ch = input.charAt(i++);
1547 if (ch == '?' && i < input.length()) {
1548 ch2 = input.charAt(i++);
1552 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1556 } else if (ch == '\n') {
1562 } else if (ch == '"') {
1564 while (i < input.length()) {
1565 ch = input.charAt(i++);
1568 } else if (ch == '\\' && i < input.length()) { // escape
1570 } else if (ch == '"') {
1575 } else if (ch == '\'') {
1577 while (i < input.length()) {
1578 ch = input.charAt(i++);
1581 } else if (ch == '\\' && i < input.length()) { // escape
1583 } else if (ch == '\'') {
1590 if (ch == '?' && i < input.length()) {
1591 ch2 = input.charAt(i++);
1595 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1604 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1607 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1608 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1610 // for (int j=0;j<phpList.size();j++) {
1611 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1612 // int startIndx = temp.length()-10;
1613 // if (startIndx<0) {
1616 // System.out.println(temp.substring(startIndx)+"?>");
1618 phpParserTester(null, 1);
1620 // for(int j=0;j<phpList.size();j++) {
1621 // temp = (PHPString) phpList.get(j);
1622 // parser.start(temp.getPHPString(), temp.getLineNumber());
1625 } catch (CoreException e) {
1629 public void phpParserTester(String s, int rowCount) throws CoreException {
1632 if (phpList.size() != 0) {
1633 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1636 this.token = TT_EOF;
1638 this.rowCount = rowCount;
1639 this.columnCount = 0;
1640 this.phpEnd = false;
1641 this.phpMode = true;
1645 if (token != TT_EOF && token != TT_UNDEFINED) {
1648 if (token != TT_EOF && token != TT_UNDEFINED) {
1649 if (token == TT_ARGCLOSE) {
1650 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1652 if (token == TT_LISTCLOSE) {
1653 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1655 if (token == TT_PARTCLOSE) {
1656 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1659 if (token == TT_ARGOPEN) {
1660 throwSyntaxError("Read character '('; end-of-file not reached.");
1662 if (token == TT_LISTOPEN) {
1663 throwSyntaxError("Read character '{'; end-of-file not reached.");
1665 if (token == TT_PARTOPEN) {
1666 throwSyntaxError("Read character '['; end-of-file not reached.");
1669 throwSyntaxError("End-of-file not reached.");
1672 } catch (SyntaxError err) {
1676 setMarker(err.getMessage(), err.getLine(), ERROR);
1678 // if an error occured,
1679 // try to find keywords 'class' or 'function'
1680 // to parse the rest of the string
1681 while (token != TT_EOF && token != TT_UNDEFINED) {
1682 if (token == TT_class || token == TT_function) {
1687 if (token == TT_EOF || token == TT_UNDEFINED) {
1696 * Parses a string with php tags
1697 * i.e. '<body> <?php phpinfo() ?> </body>'
1699 public void parse(String s) throws CoreException {
1701 this.token = TT_EOF;
1704 this.columnCount = 0;
1705 this.phpEnd = false;
1706 this.phpMode = false;
1710 if (token != TT_EOF && token != TT_UNDEFINED) {
1713 if (token != TT_EOF && token != TT_UNDEFINED) {
1714 if (token == TT_ARGCLOSE) {
1715 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1717 if (token == TT_LISTCLOSE) {
1718 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1720 if (token == TT_PARTCLOSE) {
1721 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1724 if (token == TT_ARGOPEN) {
1725 throwSyntaxError("Read character '('; end-of-file not reached.");
1727 if (token == TT_LISTOPEN) {
1728 throwSyntaxError("Read character '{'; end-of-file not reached.");
1730 if (token == TT_PARTOPEN) {
1731 throwSyntaxError("Read character '['; end-of-file not reached.");
1734 throwSyntaxError("End-of-file not reached.");
1737 } catch (SyntaxError sytaxErr1) {
1738 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1740 // if an error occured,
1741 // try to find keywords 'class' or 'function'
1742 // to parse the rest of the string
1743 while (token != TT_EOF && token != TT_UNDEFINED) {
1744 if (token == TT_class || token == TT_function) {
1749 if (token == TT_EOF || token == TT_UNDEFINED) {
1752 } catch (SyntaxError sytaxErr2) {
1753 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1761 public PHPOutlineInfo parseInfo(Object parent, String s) {
1762 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1763 // Stack stack = new Stack();
1764 // stack.push(outlineInfo.getDeclarations());
1767 this.token = TT_EOF;
1770 this.columnCount = 0;
1771 this.phpEnd = false;
1772 this.phpMode = false;
1776 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1777 } catch (CoreException e) {
1782 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPClassDeclaration current, boolean goBack) {
1783 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1784 PHPClassDeclaration temp;
1788 while (token != TT_EOF && token != TT_UNDEFINED) {
1789 if (token == TT_VARIABLE) {
1790 outlineInfo.addVariable(identifier);
1792 } else if (token == TT_function) {
1794 if (token == TT_IDENTIFIER) {
1795 outlineInfo.addVariable(identifier);
1796 current.add(new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length()));
1799 } else if (token == TT_class) {
1801 if (token == TT_IDENTIFIER) {
1802 outlineInfo.addVariable(identifier);
1803 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1805 // stack.push(temp);
1807 while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1810 parseDeclarations(outlineInfo, temp, true);
1813 } else if (token == TT_LISTOPEN) {
1816 } else if (token == TT_LISTCLOSE) {
1819 if (counter == 0 && goBack) {
1826 } catch (CoreException e) {
1830 private void statementList() throws CoreException {
1833 if ((token == TT_LISTCLOSE)
1834 || (token == TT_case)
1835 || (token == TT_default)
1836 || (token == TT_elseif)
1837 || (token == TT_endif)
1838 || (token == TT_endfor)
1839 || (token == TT_endforeach)
1840 || (token == TT_endwhile)
1841 || (token == TT_endswitch)
1842 || (token == TT_EOF)
1843 || (token == TT_UNDEFINED)) {
1849 private void compoundStatement() throws CoreException {
1850 // '{' [statement-list] '}'
1851 if (token == TT_LISTOPEN) {
1854 throwSyntaxError("'{' expected in compound-statement.");
1856 if (token != TT_LISTCLOSE) {
1859 if (token == TT_LISTCLOSE) {
1862 throwSyntaxError("'}' expected in compound-statement.");
1866 private void statement() throws CoreException {
1867 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1868 String keyword = identifier;
1869 if (token == TT_include || token == TT_include_once) {
1872 if (token == TT_SEMICOLON) {
1876 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1881 } else if (token == TT_require || token == TT_require_once) {
1885 if (token == TT_SEMICOLON) {
1889 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1894 } else if (token == TT_if) {
1896 if (token == TT_ARGOPEN) {
1899 throwSyntaxError("'(' expected after 'if' keyword.");
1902 if (token == TT_ARGCLOSE) {
1905 throwSyntaxError("')' expected after 'if' condition.");
1910 } else if (token == TT_switch) {
1912 if (token == TT_ARGOPEN) {
1915 throwSyntaxError("'(' expected after 'switch' keyword.");
1918 if (token == TT_ARGCLOSE) {
1921 throwSyntaxError("')' expected after 'switch' condition.");
1925 } else if (token == TT_for) {
1927 if (token == TT_ARGOPEN) {
1930 throwSyntaxError("'(' expected after 'for' keyword.");
1932 if (token == TT_SEMICOLON) {
1936 if (token == TT_SEMICOLON) {
1939 throwSyntaxError("';' expected after 'for'.");
1942 if (token == TT_SEMICOLON) {
1946 if (token == TT_SEMICOLON) {
1949 throwSyntaxError("';' expected after 'for'.");
1952 if (token == TT_ARGCLOSE) {
1956 if (token == TT_ARGCLOSE) {
1959 throwSyntaxError("')' expected after 'for'.");
1964 } else if (token == TT_while) {
1966 if (token == TT_ARGOPEN) {
1969 throwSyntaxError("'(' expected after 'while' keyword.");
1972 if (token == TT_ARGCLOSE) {
1975 throwSyntaxError("')' expected after 'while' condition.");
1979 } else if (token == TT_do) {
1981 if (token == TT_LISTOPEN) {
1984 throwSyntaxError("'{' expected after 'do' keyword.");
1986 if (token != TT_LISTCLOSE) {
1989 if (token == TT_LISTCLOSE) {
1992 throwSyntaxError("'}' expected after 'do' keyword.");
1994 if (token == TT_while) {
1996 if (token == TT_ARGOPEN) {
1999 throwSyntaxError("'(' expected after 'while' keyword.");
2002 if (token == TT_ARGCLOSE) {
2005 throwSyntaxError("')' expected after 'while' condition.");
2008 throwSyntaxError("'while' expected after 'do' keyword.");
2010 if (token == TT_SEMICOLON) {
2014 throwSyntaxError("';' expected after do-while statement.");
2019 } else if (token == TT_foreach) {
2021 if (token == TT_ARGOPEN) {
2024 throwSyntaxError("'(' expected after 'foreach' keyword.");
2027 if (token == TT_as) {
2030 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2033 if (token == TT_FOREACH) {
2037 if (token == TT_ARGCLOSE) {
2040 throwSyntaxError("')' expected after 'foreach' expression.");
2045 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2047 if (token != TT_SEMICOLON) {
2050 if (token == TT_SEMICOLON) {
2054 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2060 } else if (token == TT_echo) {
2063 if (token == TT_SEMICOLON) {
2067 throwSyntaxError("';' expected after 'echo' statement.");
2072 // } else if (token == TT_print) {
2075 // if (token == TT_SEMICOLON) {
2079 // throwSyntaxError("';' expected after 'print' statement.");
2085 } else if (token == TT_global || token == TT_static) {
2088 if (token == TT_SEMICOLON) {
2092 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2098 // } else if (token == TT_unset) {
2100 // if (token == TT_ARGOPEN) {
2103 // throwSyntaxError("'(' expected after 'unset' keyword.");
2106 // if (token == TT_ARGCLOSE) {
2109 // throwSyntaxError("')' expected after 'unset' statement.");
2111 // if (token == TT_SEMICOLON) {
2115 // throwSyntaxError("';' expected after 'unset' statement.");
2121 // } else if (token == TT_exit || token == TT_die) {
2123 // if (token != TT_SEMICOLON) {
2126 // if (token == TT_SEMICOLON) {
2130 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2136 } else if (token == TT_define) {
2138 if (token == TT_ARGOPEN) {
2141 throwSyntaxError("'(' expected after 'define' keyword.");
2144 if (token == TT_COMMA) {
2147 throwSyntaxError("',' expected after first 'define' constant.");
2150 if (token == TT_COMMA) {
2154 if (token == TT_ARGCLOSE) {
2157 throwSyntaxError("')' expected after 'define' statement.");
2159 if (token == TT_SEMICOLON) {
2163 throwSyntaxError("';' expected after 'define' statement.");
2168 } else if (token == TT_function) {
2170 functionDefinition();
2172 } else if (token == TT_class) {
2178 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2179 } else if (token == TT_LISTOPEN) {
2180 // compoundStatement
2182 if (token != TT_LISTCLOSE) {
2185 if (token == TT_LISTCLOSE) {
2189 throwSyntaxError("'}' expected.");
2192 if (token != TT_SEMICOLON) {
2195 if (token == TT_SEMICOLON) {
2200 throwSyntaxError("';' expected after expression.");
2207 private void classDeclarator() throws CoreException {
2209 //identifier 'extends' identifier
2210 if (token == TT_IDENTIFIER) {
2212 if (token == TT_extends) {
2214 if (token == TT_IDENTIFIER) {
2217 throwSyntaxError("Class name expected after keyword 'extends'.");
2221 throwSyntaxError("Class name expected after keyword 'class'.");
2225 private void classBody() throws CoreException {
2226 //'{' [class-element-list] '}'
2227 if (token == TT_LISTOPEN) {
2229 if (token != TT_LISTCLOSE) {
2232 if (token == TT_LISTCLOSE) {
2235 throwSyntaxError("'}' expected at end of class body.");
2238 throwSyntaxError("'{' expected at start of class body.");
2242 private void classElementList() throws CoreException {
2245 } while (token == TT_function || token == TT_var);
2248 private void classElement() throws CoreException {
2250 //function-definition
2251 if (token == TT_function) {
2253 functionDefinition();
2254 } else if (token == TT_var) {
2258 throwSyntaxError("'function' or 'var' expected.");
2262 private void classProperty() throws CoreException {
2263 //'var' variable ';'
2264 //'var' variable '=' constant ';'
2266 if (token == TT_VARIABLE) {
2268 if (token == TT_ASSIGN) {
2273 throwSyntaxError("Variable expected after keyword 'var'.");
2275 if (token != TT_COMMA) {
2280 if (token == TT_SEMICOLON) {
2283 throwSyntaxError("';' expected after variable declaration.");
2287 private void functionDefinition() throws CoreException {
2288 functionDeclarator();
2289 compoundStatement();
2292 private void functionDeclarator() throws CoreException {
2293 //identifier '(' [parameter-list] ')'
2294 if (token == TT_AMPERSAND) {
2297 if (token == TT_IDENTIFIER) {
2299 if (token == TT_ARGOPEN) {
2302 throwSyntaxError("'(' expected in function declaration.");
2304 if (token != TT_ARGCLOSE) {
2307 if (token != TT_ARGCLOSE) {
2308 throwSyntaxError("')' expected in function declaration.");
2315 private void parameterList() throws CoreException {
2316 //parameter-declaration
2317 //parameter-list ',' parameter-declaration
2319 parameterDeclaration();
2320 if (token != TT_COMMA) {
2327 private void parameterDeclaration() throws CoreException {
2329 //variable-reference
2330 if (token == TT_AMPERSAND) {
2332 if (token == TT_VARIABLE) {
2335 throwSyntaxError("Variable expected after reference operator '&'.");
2338 //variable '=' constant
2339 if (token == TT_VARIABLE) {
2341 if (token == TT_ASSIGN) {
2349 private void labeledStatementList() throws CoreException {
2350 if (token != TT_case && token != TT_default) {
2351 throwSyntaxError("'case' or 'default' expected.");
2354 if (token == TT_case) {
2357 if (token == TT_DDOT) {
2359 if (token == TT_case || token == TT_default) { // empty case statement ?
2363 } else if (token == TT_SEMICOLON) {
2364 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2366 if (token == TT_case) { // empty case statement ?
2371 throwSyntaxError("':' character after 'case' constant expected.");
2373 } else { // TT_default
2375 if (token == TT_DDOT) {
2379 throwSyntaxError("':' character after 'default' expected.");
2382 } while (token == TT_case || token == TT_default);
2385 // public void labeledStatement() {
2386 // if (token == TT_case) {
2389 // if (token == TT_DDOT) {
2393 // throwSyntaxError("':' character after 'case' constant expected.");
2396 // } else if (token == TT_default) {
2398 // if (token == TT_DDOT) {
2402 // throwSyntaxError("':' character after 'default' expected.");
2408 // public void expressionStatement() {
2411 // private void inclusionStatement() {
2414 // public void compoundStatement() {
2417 // public void selectionStatement() {
2420 // public void iterationStatement() {
2423 // public void jumpStatement() {
2426 // public void outputStatement() {
2429 // public void scopeStatement() {
2432 // public void flowStatement() {
2435 // public void definitionStatement() {
2438 private void ifStatement() throws CoreException {
2439 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2440 if (token == TT_DDOT) {
2446 if (token == TT_DDOT) {
2450 if (token == TT_if) { //'else if'
2452 elseifStatementList();
2454 throwSyntaxError("':' expected after 'else'.");
2460 elseifStatementList();
2464 if (token != TT_endif) {
2465 throwSyntaxError("'endif' expected.");
2468 if (token != TT_SEMICOLON) {
2469 throwSyntaxError("';' expected after if-statement.");
2473 // statement [else-statement]
2475 if (token == TT_elseif) {
2477 if (token == TT_ARGOPEN) {
2480 throwSyntaxError("'(' expected after 'elseif' keyword.");
2483 if (token == TT_ARGCLOSE) {
2486 throwSyntaxError("')' expected after 'elseif' condition.");
2489 } else if (token == TT_else) {
2496 private void elseifStatementList() throws CoreException {
2502 if (token == TT_DDOT) {
2507 if (token == TT_if) { //'else if'
2510 throwSyntaxError("':' expected after 'else'.");
2523 private void elseifStatement() throws CoreException {
2524 if (token == TT_ARGOPEN) {
2527 if (token != TT_ARGOPEN) {
2528 throwSyntaxError("')' expected in else-if-statement.");
2531 if (token != TT_DDOT) {
2532 throwSyntaxError("':' expected in else-if-statement.");
2539 private void switchStatement() throws CoreException {
2540 if (token == TT_DDOT) {
2541 // ':' [labeled-statement-list] 'endswitch' ';'
2543 labeledStatementList();
2544 if (token != TT_endswitch) {
2545 throwSyntaxError("'endswitch' expected.");
2548 if (token != TT_SEMICOLON) {
2549 throwSyntaxError("';' expected after switch-statement.");
2553 // '{' [labeled-statement-list] '}'
2554 if (token != TT_LISTOPEN) {
2555 throwSyntaxError("'{' expected in switch statement.");
2558 if (token != TT_LISTCLOSE) {
2559 labeledStatementList();
2561 if (token != TT_LISTCLOSE) {
2562 throwSyntaxError("'}' expected in switch statement.");
2569 private void forStatement() throws CoreException {
2570 if (token == TT_DDOT) {
2573 if (token != TT_endfor) {
2574 throwSyntaxError("'endfor' expected.");
2577 if (token != TT_SEMICOLON) {
2578 throwSyntaxError("';' expected after for-statement.");
2586 private void whileStatement() throws CoreException {
2587 // ':' statement-list 'endwhile' ';'
2588 if (token == TT_DDOT) {
2591 if (token != TT_endwhile) {
2592 throwSyntaxError("'endwhile' expected.");
2595 if (token != TT_SEMICOLON) {
2596 throwSyntaxError("';' expected after while-statement.");
2604 private void foreachStatement() throws CoreException {
2605 if (token == TT_DDOT) {
2608 if (token != TT_endforeach) {
2609 throwSyntaxError("'endforeach' expected.");
2612 if (token != TT_SEMICOLON) {
2613 throwSyntaxError("';' expected after foreach-statement.");
2621 private void exitStatus() throws CoreException {
2622 if (token == TT_ARGOPEN) {
2625 throwSyntaxError("'(' expected in 'exit-status'.");
2627 if (token != TT_ARGCLOSE) {
2630 if (token == TT_ARGCLOSE) {
2633 throwSyntaxError("')' expected after 'exit-status'.");
2637 private void expressionList() throws CoreException {
2640 if (token == TT_COMMA) {
2648 private void expression() throws CoreException {
2649 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2652 logicalinclusiveorExpression();
2653 // while (token != TT_SEMICOLON) {
2659 private void postfixExpression() throws CoreException {
2661 boolean castFlag = false;
2676 case TT_STRING_CONSTANT :
2679 case TT_INTERPOLATED_STRING :
2684 if (token == TT_IDENTIFIER) {
2685 // check if identifier is a type:
2687 String str = identifier.toLowerCase();
2688 for (int i = 0; i < PHP_TYPES.length; i++) {
2689 if (PHP_TYPES[i].equals(str)) {
2696 if (token != TT_ARGCLOSE) {
2697 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2707 if (token != TT_ARGCLOSE) {
2708 throwSyntaxError(") expected in postfix-expression.");
2712 case TT_DOUBLE_NUMBER :
2715 case TT_INT_NUMBER :
2718 case TT_DOLLAROPEN :
2721 if (token != TT_LISTCLOSE) {
2722 throwSyntaxError("'}' expected after indirect variable token '${'.");
2729 if (token == TT_LISTOPEN) {
2732 if (token != TT_LISTCLOSE) {
2733 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2736 } else if (token == TT_ARGOPEN) {
2738 if (token != TT_ARGCLOSE) {
2740 if (token != TT_ARGCLOSE) {
2741 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2747 case TT_IDENTIFIER :
2750 if (token == TT_ARGOPEN) {
2752 if (token != TT_ARGCLOSE) {
2754 if (token != TT_ARGCLOSE) {
2755 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2764 // if (token == TT_SEMICOLON) {
2768 // throwSyntaxError("';' expected after 'print' statement.");
2775 if (token == TT_ARGOPEN) {
2777 if (token == TT_COMMA) {
2781 if (token != TT_ARGCLOSE) {
2782 throwSyntaxError("')' expected after 'list' keyword.");
2785 // if (token == TT_SET) {
2787 // logicalinclusiveorExpression();
2790 throwSyntaxError("'(' expected after 'list' keyword.");
2795 // if (token != TT_SEMICOLON) {
2798 // if (token == TT_SEMICOLON) {
2802 // throwSyntaxError("';' expected after 'exit' expression.");
2809 // if (token != TT_SEMICOLON) {
2812 // if (token == TT_SEMICOLON) {
2816 // throwSyntaxError("';' expected after 'die' expression.");
2823 // if (token == TT_ARGOPEN) {
2825 // if (token == TT_COMMA) {
2828 // expressionList();
2829 // if (token != TT_ARGCLOSE) {
2830 // throwSyntaxError("')' expected after 'list' keyword.");
2833 // if (token == TT_SET) {
2835 // logicalinclusiveorExpression();
2838 // throwSyntaxError("'(' expected after 'list' keyword.");
2842 boolean while_flag = true;
2848 if (token != TT_PARTCLOSE) {
2849 throwSyntaxError("] expected in postfix-expression.");
2853 case TT_DDOT2 : // ::
2856 if (token > TT_KEYWORD) {
2858 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2864 // if (token == TT_ARGOPEN) {
2866 // expressionList();
2867 // if (token != TT_ARGCLOSE) {
2868 // throwSyntaxError(") expected after variable '" + ident + "'.");
2873 case TT_IDENTIFIER :
2880 if (token != TT_LISTCLOSE) {
2881 throwSyntaxError("} expected in postfix-expression.");
2886 throwSyntaxError("Syntax error after '->' token.");
2887 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2888 if (token == TT_PARTOPEN) {
2891 if (token != TT_PARTCLOSE) {
2892 throwSyntaxError("] expected after '->'.");
2896 if (token == TT_ARGOPEN) {
2899 if (token != TT_ARGCLOSE) {
2900 throwSyntaxError(") expected after '->'.");
2904 if (token == TT_LISTOPEN) {
2907 if (token != TT_LISTCLOSE) {
2908 throwSyntaxError("} expected after '->'.");
2928 private void unaryExpression() throws CoreException {
2938 // '@' '&' '*' '+' '-' '~' '!'
2968 postfixExpression();
2972 private void castExpression() throws CoreException {
2973 // if (token == TT_ARGOPEN) {
2976 // if (token != TT_ARGCLOSE) {
2977 // throwSyntaxError(") expected after cast-expression.");
2984 private void typeName() throws CoreException {
2985 //'string' 'unset' 'array' 'object'
2987 //'real' 'double' 'float'
2990 if (token == TT_IDENTIFIER) {
2992 String str = identifier.toLowerCase();
2994 for (int i = 0; i < PHP_TYPES.length; i++) {
2995 if (PHP_TYPES[i].equals(str)) {
3000 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3003 private void assignExpression() throws CoreException {
3005 if (token == TT_ASSIGN) { // =
3007 logicalinclusiveorExpression();
3008 } else if (token == TT_DOTASSIGN) { // .=
3010 logicalinclusiveorExpression();
3011 } else if (token == TT_FOREACH) { // =>
3013 logicalinclusiveorExpression();
3014 } else if (token == TT_ADDTO) { // +=
3016 logicalinclusiveorExpression();
3017 } else if (token == TT_SUBTRACTFROM) { // -=
3019 logicalinclusiveorExpression();
3020 } else if (token == TT_TIMESBY) { // *=
3022 logicalinclusiveorExpression();
3023 } else if (token == TT_DIVIDEBY) { // *=
3025 logicalinclusiveorExpression();
3026 } else if (token == TT_MODASSIGN) { // %=
3028 logicalinclusiveorExpression();
3029 } else if (token == TT_ANDASSIGN) { // &=
3031 logicalinclusiveorExpression();
3032 } else if (token == TT_POWASSIGN) { // ^=
3034 logicalinclusiveorExpression();
3035 } else if (token == TT_LSHIFTASSIGN) { // <<=
3037 logicalinclusiveorExpression();
3038 } else if (token == TT_RSHIFTASSIGN) { // >>=
3040 logicalinclusiveorExpression();
3041 } else if (token == TT_TILDEASSIGN) { // ~=
3043 logicalinclusiveorExpression();
3047 private void multiplicativeExpression() throws CoreException {
3050 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3057 private void concatenationExpression() throws CoreException {
3059 multiplicativeExpression();
3060 if (token != TT_DOT) {
3067 private void additiveExpression() throws CoreException {
3069 concatenationExpression();
3070 if (token != TT_ADD && token != TT_SUBTRACT) {
3077 private void shiftExpression() throws CoreException {
3079 additiveExpression();
3080 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3087 private void relationalExpression() throws CoreException {
3090 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3097 private void identicalExpression() throws CoreException {
3099 relationalExpression();
3100 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3107 private void equalityExpression() throws CoreException {
3109 identicalExpression();
3110 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3117 private void ternaryExpression() throws CoreException {
3118 equalityExpression();
3119 if (token == TT_QUESTIONMARK) {
3122 if (token == TT_DDOT) {
3126 throwSyntaxError("':' expected in ternary operator '? :'.");
3131 private void andExpression() throws CoreException {
3133 ternaryExpression();
3134 if (token != TT_AMPERSAND) {
3141 private void exclusiveorExpression() throws CoreException {
3144 if (token != TT_POW) {
3151 private void inclusiveorExpression() throws CoreException {
3153 exclusiveorExpression();
3154 if (token != TT_LINE) {
3161 private void booleanandExpression() throws CoreException {
3163 inclusiveorExpression();
3164 if (token != TT_AND) {
3171 private void booleanorExpression() throws CoreException {
3173 booleanandExpression();
3174 if (token != TT_OR) {
3181 private void logicalandExpression() throws CoreException {
3183 booleanorExpression();
3184 if (token != TT_and) {
3191 private void logicalexclusiveorExpression() throws CoreException {
3193 logicalandExpression();
3194 if (token != TT_xor) {
3201 private void logicalinclusiveorExpression() throws CoreException {
3203 logicalexclusiveorExpression();
3204 if (token != TT_or) {
3211 // public void assignmentExpression() {
3212 // if (token == TT_VARIABLE) {
3214 // if (token == TT_SET) {
3216 // logicalinclusiveorExpression();
3219 // logicalinclusiveorExpression();
3223 private void variableList() throws CoreException {
3226 if (token == TT_COMMA) {
3234 private void variable() throws CoreException {
3235 if (token == TT_DOLLAROPEN) {
3239 if (token != TT_LISTCLOSE) {
3240 throwSyntaxError("'}' expected after indirect variable token '${'.");
3244 if (token == TT_VARIABLE) {
3246 if (token == TT_PARTOPEN) {
3249 if (token != TT_PARTCLOSE) {
3250 throwSyntaxError("']' expected in variable-list.");
3253 } else if (token == TT_ASSIGN) {
3258 throwSyntaxError("$-variable expected in variable-list.");
3263 private void constant() throws CoreException {
3269 case TT_DOUBLE_NUMBER :
3272 case TT_INT_NUMBER :
3276 throwSyntaxError("Constant expected after '+' presign.");
3282 case TT_DOUBLE_NUMBER :
3285 case TT_INT_NUMBER :
3289 throwSyntaxError("Constant expected after '-' presign.");
3301 case TT_IDENTIFIER :
3304 if (token == TT_ARGOPEN) {
3306 if (token != TT_ARGCLOSE) {
3308 if (token != TT_ARGCLOSE) {
3309 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3315 case TT_STRING_CONSTANT :
3318 case TT_INTERPOLATED_STRING :
3321 case TT_DOUBLE_NUMBER :
3324 case TT_INT_NUMBER :
3328 throwSyntaxError("Constant expected.");
3333 * Call the php parse command ( php -l -f <filename> )
3334 * and create markers according to the external parser output
3336 public static void phpExternalParse(IFile file) {
3337 //IFile file = (IFile) resource;
3338 IPath path = file.getFullPath();
3339 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3340 String filename = file.getLocation().toString();
3342 String[] arguments = { filename };
3343 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3344 String command = form.format(arguments);
3346 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3349 // parse the buffer to find the errors and warnings
3350 createMarkers(parserResult, file);
3351 } catch (CoreException e) {
3356 * Create markers according to the external parser output
3358 private static void createMarkers(String output, IFile file) throws CoreException {
3359 // delete all markers
3360 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3364 boolean flag = true;
3365 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3366 // newer php error output (tested with 4.2.3)
3367 scanLine(output, file, indx, brIndx);
3372 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3373 // older php error output (tested with 4.2.3)
3374 scanLine(output, file, indx, brIndx);
3380 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3382 String outLineNumberString;
3383 StringBuffer lineNumberBuffer = new StringBuffer(10);
3385 current = output.substring(indx, brIndx);
3387 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3388 int onLine = current.indexOf("on line <b>");
3390 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3391 for (int i = onLine; i < current.length(); i++) {
3392 ch = current.charAt(i);
3393 if ('0' <= ch && '9' >= ch) {
3394 lineNumberBuffer.append(ch);
3398 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3400 Hashtable attributes = new Hashtable();
3402 current = current.replaceAll("\n", "");
3403 current = current.replaceAll("<b>", "");
3404 current = current.replaceAll("</b>", "");
3405 MarkerUtilities.setMessage(attributes, current);
3407 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3408 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3409 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3410 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3412 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3413 MarkerUtilities.setLineNumber(attributes, lineNumber);
3414 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);