1 /**********************************************************************
2 Copyright (c) 2002 Klaus Hartlage - www.eclipseproject.de
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
9 Klaus Hartlage - www.eclipseproject.de
10 **********************************************************************/
11 package net.sourceforge.phpeclipse.phpeditor.phpparser;
13 import java.text.MessageFormat;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.Hashtable;
18 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
19 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
20 import net.sourceforge.phpeclipse.phpeditor.PHPString;
21 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
22 import org.eclipse.core.resources.IFile;
23 import org.eclipse.core.resources.IMarker;
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.jface.preference.IPreferenceStore;
27 import org.eclipse.ui.texteditor.MarkerUtilities;
29 public class PHPParser extends PHPKeywords {
30 // strings for external parser call
31 private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
32 private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
34 public static final int ERROR = 2;
35 public static final int WARNING = 1;
36 public static final int INFO = 0;
37 private IFile fileToParse;
38 private ArrayList phpList;
40 private int currentPHPString;
41 private boolean phpEnd;
43 private static HashMap keywordMap = null;
51 // row counter for syntax errors:
53 // column counter for syntax errors:
65 private boolean phpMode;
67 final static int TT_EOF = 0;
68 final static int TT_UNDEFINED = 1;
69 final static int TT_HTML = 2;
71 final static int TT_MOD = 30;
72 final static int TT_NOT = 31;
73 final static int TT_DOT = 32;
74 final static int TT_POW = 33;
75 final static int TT_DIV = 34;
76 final static int TT_MULTIPLY = 35;
77 final static int TT_SUBTRACT = 36;
78 final static int TT_ADD = 37;
79 final static int TT_EQUAL = 38;
80 final static int TT_UNEQUAL = 39;
81 final static int TT_GREATER = 40;
82 final static int TT_GREATEREQUAL = 41;
83 final static int TT_LESS = 42;
84 final static int TT_LESSEQUAL = 43;
85 final static int TT_AND = 44;
86 final static int TT_OR = 45;
87 final static int TT_HASH = 46;
88 final static int TT_DDOT = 47;
89 final static int TT_DOTASSIGN = 48;
91 final static int TT_ASSIGN = 49;
92 final static int TT_REF = 50;
93 final static int TT_FOREACH = 51;
94 final static int TT_AMPERSAND = 52;
95 final static int TT_DOLLARLISTOPEN = 53;
96 final static int TT_TILDE = 54;
97 final static int TT_TILDEASSIGN = 55;
98 final static int TT_MODASSIGN = 56;
99 final static int TT_POWASSIGN = 57;
100 final static int TT_RSHIFTASSIGN = 58;
101 final static int TT_LSHIFTASSIGN = 59;
102 final static int TT_ANDASSIGN = 60;
103 final static int TT_QUESTIONMARK = 61;
104 final static int TT_DDOT2 = 62;
105 final static int TT_AT = 63;
106 // final static int TT_HEREDOC = 64;
108 final static int TT_DOLLAROPEN = 127;
109 final static int TT_ARGOPEN = 128;
110 final static int TT_ARGCLOSE = 129;
111 final static int TT_LISTOPEN = 130;
112 final static int TT_LISTCLOSE = 131;
113 final static int TT_PARTOPEN = 132;
114 final static int TT_PARTCLOSE = 133;
115 final static int TT_COMMA = 134;
117 final static int TT_STRING = 136;
118 final static int TT_IDENTIFIER = 138;
119 final static int TT_DIGIT = 139;
120 final static int TT_SEMICOLON = 140;
121 final static int TT_SLOT = 141;
122 final static int TT_SLOTSEQUENCE = 142;
123 final static int TT_DECREMENT = 144;
124 final static int TT_INCREMENT = 145;
125 final static int TT_ADDTO = 146;
126 final static int TT_DIVIDEBY = 147;
127 final static int TT_SUBTRACTFROM = 148;
128 final static int TT_TIMESBY = 149;
129 final static int TT_VARIABLE = 150;
130 final static int TT_INT_NUMBER = 151;
131 final static int TT_DOUBLE_NUMBER = 152;
132 final static int TT_INTERPOLATED_STRING = 153;
133 final static int TT_STRING_CONSTANT = 154;
135 final static int TT_LSHIFT = 155;
136 final static int TT_RSHIFT = 156;
137 final static int TT_EX_EQUAL = 157;
138 final static int TT_EX_UNEQUAL = 158;
139 final static int TT_LINE = 159;
140 // final static int TT_AT = 153; // @
145 *@param sess Description of Parameter
148 public PHPParser(IFile fileToParse) {
149 if (keywordMap == null) {
150 keywordMap = new HashMap();
151 for (int i = 0; i < PHP_KEYWORS.length; i++) {
152 keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
155 this.currentPHPString = 0;
156 this.fileToParse = fileToParse;
162 this.columnCount = 0;
169 * Create marker for the parse error
171 private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
172 setMarker(fileToParse, message, lineNumber, errorLevel);
175 public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
177 Hashtable attributes = new Hashtable();
178 MarkerUtilities.setMessage(attributes, message);
179 switch (errorLevel) {
181 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
184 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
187 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
190 MarkerUtilities.setLineNumber(attributes, lineNumber);
191 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
195 private void throwSyntaxError(String error) {
197 if (str.length() < chIndx) {
200 // read until end-of-line
202 while (str.length() > eol) {
203 ch = str.charAt(eol++);
209 throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
212 private void throwSyntaxError(String error, int startRow) {
214 throw new SyntaxError(startRow, 0, " ", error);
218 * Method Declaration.
222 private void getChar() {
223 if (str.length() > chIndx) {
224 ch = str.charAt(chIndx++);
229 chIndx = str.length() + 1;
235 private void getNextToken_OldVersion() throws CoreException {
238 while (str.length() > chIndx) {
239 ch = str.charAt(chIndx++);
240 token = TT_UNDEFINED;
243 columnCount = chIndx;
244 continue; // while loop
246 if (str.length() == chIndx) {
249 if (!Character.isWhitespace(ch)) {
251 if (str.length() > chIndx) {
252 if (str.charAt(chIndx) == '{') {
254 token = TT_DOLLAROPEN;
261 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
265 if (ch >= '0' && ch <= '9') {
270 if (str.length() > chIndx) {
271 if (str.charAt(chIndx) == '/') {
273 // read comment until end of line:
274 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
278 } else if (str.charAt(chIndx) == '*') {
280 // multi line comment:
281 while (str.length() > chIndx) {
282 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
286 ch = str.charAt(chIndx++);
289 columnCount = chIndx;
295 } else if (ch == '#') {
296 // read comment until end of line:
297 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
301 } else if (ch == '"') {
302 // read string until end
303 boolean openString = true;
304 while (str.length() > chIndx) {
305 ch = str.charAt(chIndx++);
307 if (str.length() > chIndx) {
308 ch = str.charAt(chIndx++);
310 } else if (ch == '"') {
313 } else if (ch == '\n') {
315 columnCount = chIndx;
319 throwSyntaxError("Open string character '\"' at end of file.");
321 token = TT_INTERPOLATED_STRING;
323 } else if (ch == '\'') {
324 // read string until end
325 boolean openString = true;
326 int startRow = rowCount;
327 while (str.length() > chIndx) {
328 ch = str.charAt(chIndx++);
330 if (str.length() > chIndx) {
331 ch = str.charAt(chIndx++);
333 } else if (ch == '\'') {
336 } else if (ch == '\n') {
338 columnCount = chIndx;
342 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
344 token = TT_STRING_CONSTANT;
346 } else if (ch == '`') {
347 // read string until end
348 boolean openString = true;
349 int startRow = rowCount;
350 while (str.length() > chIndx) {
351 ch = str.charAt(chIndx++);
353 if (str.length() > chIndx) {
354 ch = str.charAt(chIndx++);
356 } else if (ch == '`') {
359 } else if (ch == '\n') {
361 columnCount = chIndx;
365 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
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 getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
887 } else if (ch == '\'') {
888 getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
890 } else if (ch == '`') {
891 getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
892 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
911 token = TT_LISTCLOSE;
919 token = TT_PARTCLOSE;
927 token = TT_QUESTIONMARK;
928 if (str.length() > chIndx) {
929 if (str.charAt(chIndx) == '>') {
945 if (str.length() > chIndx) {
946 if (str.charAt(chIndx) == '=') {
948 token = TT_TILDEASSIGN;
956 if (str.length() > chIndx) {
957 if (str.charAt(chIndx) == '=') {
959 token = TT_DOTASSIGN;
972 if (str.length() > chIndx) {
973 if (str.charAt(chIndx) == '=') {
975 token = TT_MODASSIGN;
982 token = TT_SEMICOLON;
987 if (str.length() > chIndx) {
988 if (str.charAt(chIndx) == '=') {
990 token = TT_POWASSIGN;
999 if (str.length() > chIndx) {
1000 if (str.charAt(chIndx) == '=') {
1002 token = TT_DIVIDEBY;
1010 token = TT_MULTIPLY;
1011 if (str.length() > chIndx) {
1012 if (str.charAt(chIndx) == '*') {
1018 if (str.charAt(chIndx) == '=') {
1029 if (str.length() > chIndx) {
1030 if (str.charAt(chIndx) == '+') {
1032 token = TT_INCREMENT;
1036 if (str.charAt(chIndx) == '=') {
1045 token = TT_SUBTRACT;
1046 if (str.length() > chIndx) {
1047 if (str.charAt(chIndx) == '-') {
1049 token = TT_DECREMENT;
1053 if (str.charAt(chIndx) == '=') {
1055 token = TT_SUBTRACTFROM;
1059 if (str.charAt(chIndx) == '>') {
1071 if (str.length() > chIndx) {
1072 ch = str.charAt(chIndx);
1077 if (str.length() > chIndx) {
1078 ch = str.charAt(chIndx);
1082 token = TT_EX_EQUAL;
1099 if (str.length() > chIndx) {
1100 if (str.charAt(chIndx) == '=') {
1103 if (str.length() > chIndx) {
1104 ch = str.charAt(chIndx);
1108 token = TT_EX_UNEQUAL;
1119 if (str.length() > chIndx) {
1120 if (str.charAt(chIndx) == '=') {
1122 token = TT_GREATEREQUAL;
1125 if (str.charAt(chIndx) == '>') {
1128 if (str.length() > chIndx) {
1129 if (str.charAt(chIndx) == '=') {
1131 token = TT_RSHIFTASSIGN;
1143 if (str.length() > chIndx) {
1144 if (str.charAt(chIndx) == '=') {
1146 token = TT_LESSEQUAL;
1150 if (str.charAt(chIndx) == '<') {
1153 if (str.charAt(chIndx) == '<') {
1155 int startRow = rowCount;
1156 if (str.length() > chIndx) {
1158 ch = str.charAt(++chIndx);
1159 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1162 token = TT_STRING_CONSTANT;
1163 while (str.length() > chIndx) {
1164 ch = str.charAt(chIndx++);
1166 if (str.length() >= chIndx + identifier.length()) {
1167 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1168 chIndx += identifier.length();
1176 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1177 } else if (str.charAt(chIndx) == '=') {
1179 token = TT_LSHIFTASSIGN;
1191 if (str.length() > chIndx) {
1192 if (str.charAt(chIndx) == '|') {
1202 token = TT_AMPERSAND;
1203 if (str.length() > chIndx) {
1204 if (str.charAt(chIndx) == '&') {
1209 if (str.charAt(chIndx) == '=') {
1211 token = TT_ANDASSIGN;
1220 if (str.length() > chIndx) {
1221 if (str.charAt(chIndx) == ':') {
1236 throwSyntaxError("unexpected character: '" + ch + "'");
1239 if (token == TT_UNDEFINED) {
1240 throwSyntaxError("token not found");
1247 } catch (StringIndexOutOfBoundsException e) {
1248 // catched from charAt
1251 chIndx = str.length() + 1;
1256 // if (phpList != null) {
1257 // if (currentPHPString < phpList.size()) {
1258 // token = TT_UNDEFINED;
1259 // temp = (PHPString) phpList.get(currentPHPString++);
1260 // this.str = temp.getPHPString();
1261 // this.token = TT_EOF;
1263 // this.rowCount = temp.getLineNumber();
1264 // this.columnCount = 0;
1268 // token = TT_UNDEFINED;
1275 private void getIdentifier() {
1276 StringBuffer ident = new StringBuffer();
1281 // attention recursive call:
1283 token = TT_VARIABLE;
1286 token = TT_IDENTIFIER;
1290 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1294 identifier = ident.toString();
1297 // determine if this identitfer is a keyword
1298 // @todo improve this in future version
1299 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1301 token = i.intValue();
1305 private void getNumber() {
1306 StringBuffer inum = new StringBuffer();
1315 // determine number conversions:
1316 if (firstCh == '0') {
1345 if (numFormat == 16) {
1346 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1351 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1352 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1353 if (ch == '.' && dFlag != ' ') {
1356 if ((dFlag == 'E') || (dFlag == 'e')) {
1362 if ((ch == '-') || (ch == '+')) {
1376 doubleNumber = new Double(inum.toString());
1377 token = TT_DOUBLE_NUMBER;
1380 longNumber = Long.valueOf(inum.toString(), numFormat);
1381 token = TT_INT_NUMBER;
1385 } catch (Throwable e) {
1386 throwSyntaxError("Number format error: " + inum.toString());
1392 * @param openChar the opening char ('\'', '"', '`')
1393 * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
1394 * @param errorMsg the error message in case of parse error in the string
1396 private void getString(final char openChar, final int typeString, final String errorMsg) {
1397 StringBuffer sBuffer = new StringBuffer();
1398 boolean openString = true;
1399 int startRow = rowCount;
1400 while (str.length() > chIndx) {
1401 ch = str.charAt(chIndx++);
1404 if (str.length() > chIndx) {
1405 ch = str.charAt(chIndx++);
1408 } else if (ch == openChar) {
1411 } else if (ch == '\n') {
1413 columnCount = chIndx;
1419 if (typeString == TT_STRING_CONSTANT) {
1420 throwSyntaxError(errorMsg, startRow);
1422 throwSyntaxError(errorMsg);
1426 stringValue = sBuffer.toString();
1429 public void htmlParserTester(String input) {
1431 int startLineNumber = 1;
1435 boolean phpMode = false;
1436 boolean phpFound = false;
1438 phpList = new ArrayList();
1439 currentPHPString = 0;
1443 while (i < input.length()) {
1444 ch = input.charAt(i++);
1448 if ((!phpMode) && ch == '<') {
1449 ch2 = input.charAt(i++);
1451 ch2 = input.charAt(i++);
1452 if (Character.isWhitespace(ch2)) {
1457 startLineNumber = lineNumber;
1459 } else if (ch2 == 'p') {
1460 ch2 = input.charAt(i++);
1462 ch2 = input.charAt(i++);
1467 startLineNumber = lineNumber;
1473 } else if (ch2 == 'P') {
1474 ch2 = input.charAt(i++);
1476 ch2 = input.charAt(i++);
1481 startLineNumber = lineNumber;
1494 if (ch == '/' && i < input.length()) {
1495 ch2 = input.charAt(i++);
1497 while (i < input.length()) {
1498 ch = input.charAt(i++);
1499 if (ch == '?' && i < input.length()) {
1500 ch2 = input.charAt(i++);
1504 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1508 } else if (ch == '\n') {
1514 } else if (ch2 == '*') {
1515 // multi-line comment
1516 while (i < input.length()) {
1517 ch = input.charAt(i++);
1520 } else if (ch == '*' && i < input.length()) {
1521 ch2 = input.charAt(i++);
1532 } else if (ch == '#') {
1533 while (i < input.length()) {
1534 ch = input.charAt(i++);
1535 if (ch == '?' && i < input.length()) {
1536 ch2 = input.charAt(i++);
1540 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1544 } else if (ch == '\n') {
1550 } else if (ch == '"') {
1552 while (i < input.length()) {
1553 ch = input.charAt(i++);
1556 } else if (ch == '\\' && i < input.length()) { // escape
1558 } else if (ch == '"') {
1563 } else if (ch == '\'') {
1565 while (i < input.length()) {
1566 ch = input.charAt(i++);
1569 } else if (ch == '\\' && i < input.length()) { // escape
1571 } else if (ch == '\'') {
1578 if (ch == '?' && i < input.length()) {
1579 ch2 = input.charAt(i++);
1583 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1592 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1595 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1596 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1598 // for (int j=0;j<phpList.size();j++) {
1599 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1600 // int startIndx = temp.length()-10;
1601 // if (startIndx<0) {
1604 // System.out.println(temp.substring(startIndx)+"?>");
1606 phpParserTester(null, 1);
1608 // for(int j=0;j<phpList.size();j++) {
1609 // temp = (PHPString) phpList.get(j);
1610 // parser.start(temp.getPHPString(), temp.getLineNumber());
1613 } catch (CoreException e) {
1617 public void phpParserTester(String s, int rowCount) throws CoreException {
1620 if (phpList.size() != 0) {
1621 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1624 this.token = TT_EOF;
1626 this.rowCount = rowCount;
1627 this.columnCount = 0;
1628 this.phpEnd = false;
1629 this.phpMode = true;
1633 if (token != TT_EOF && token != TT_UNDEFINED) {
1636 if (token != TT_EOF && token != TT_UNDEFINED) {
1637 if (token == TT_ARGCLOSE) {
1638 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1640 if (token == TT_LISTCLOSE) {
1641 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1643 if (token == TT_PARTCLOSE) {
1644 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1647 if (token == TT_ARGOPEN) {
1648 throwSyntaxError("Read character '('; end-of-file not reached.");
1650 if (token == TT_LISTOPEN) {
1651 throwSyntaxError("Read character '{'; end-of-file not reached.");
1653 if (token == TT_PARTOPEN) {
1654 throwSyntaxError("Read character '['; end-of-file not reached.");
1657 throwSyntaxError("End-of-file not reached.");
1660 } catch (SyntaxError err) {
1664 setMarker(err.getMessage(), err.getLine(), ERROR);
1666 // if an error occured,
1667 // try to find keywords 'class' or 'function'
1668 // to parse the rest of the string
1669 while (token != TT_EOF && token != TT_UNDEFINED) {
1670 if (token == TT_class || token == TT_function) {
1675 if (token == TT_EOF || token == TT_UNDEFINED) {
1684 * Parses a string with php tags
1685 * i.e. '<body> <?php phpinfo() ?> </body>'
1687 public void parse(String s) throws CoreException {
1689 this.token = TT_EOF;
1692 this.columnCount = 0;
1693 this.phpEnd = false;
1694 this.phpMode = false;
1698 if (token != TT_EOF && token != TT_UNDEFINED) {
1701 if (token != TT_EOF && token != TT_UNDEFINED) {
1702 if (token == TT_ARGCLOSE) {
1703 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1705 if (token == TT_LISTCLOSE) {
1706 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1708 if (token == TT_PARTCLOSE) {
1709 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1712 if (token == TT_ARGOPEN) {
1713 throwSyntaxError("Read character '('; end-of-file not reached.");
1715 if (token == TT_LISTOPEN) {
1716 throwSyntaxError("Read character '{'; end-of-file not reached.");
1718 if (token == TT_PARTOPEN) {
1719 throwSyntaxError("Read character '['; end-of-file not reached.");
1722 throwSyntaxError("End-of-file not reached.");
1725 } catch (SyntaxError sytaxErr1) {
1726 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1728 // if an error occured,
1729 // try to find keywords 'class' or 'function'
1730 // to parse the rest of the string
1731 while (token != TT_EOF && token != TT_UNDEFINED) {
1732 if (token == TT_class || token == TT_function) {
1737 if (token == TT_EOF || token == TT_UNDEFINED) {
1740 } catch (SyntaxError sytaxErr2) {
1741 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1749 public PHPOutlineInfo parseInfo(Object parent, String s) {
1750 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1751 // Stack stack = new Stack();
1752 // stack.push(outlineInfo.getDeclarations());
1755 this.token = TT_EOF;
1758 this.columnCount = 0;
1759 this.phpEnd = false;
1760 this.phpMode = false;
1764 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1765 } catch (CoreException e) {
1770 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPClassDeclaration current, boolean goBack) {
1771 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1772 PHPClassDeclaration temp;
1774 String oldIdentifier;
1775 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1777 while (token != TT_EOF && token != TT_UNDEFINED) {
1778 if (token == TT_VARIABLE) {
1779 outlineInfo.addVariable(identifier);
1781 } else if (token == TT_var) {
1783 if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1785 outlineInfo.addVariable(identifier);
1786 if (token != TT_SEMICOLON) {
1787 oldIdentifier = identifier;
1790 case TT_VARIABLE : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1792 case TT_IDENTIFIER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1794 case TT_DOUBLE_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
1796 case TT_INT_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
1798 case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1800 case TT_STRING_CONSTANT : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1802 default : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
1806 current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1809 } else if (token == TT_function) {
1811 if (token == TT_AMPERSAND) {
1814 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1815 outlineInfo.addVariable(identifier);
1816 current.add(new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length()));
1819 } else if (token == TT_class) {
1821 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
1822 outlineInfo.addVariable(identifier);
1823 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1825 // stack.push(temp);
1827 while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1830 parseDeclarations(outlineInfo, temp, true);
1833 } else if (token == TT_LISTOPEN) {
1836 } else if (token == TT_LISTCLOSE) {
1839 if (counter == 0 && goBack) {
1846 } catch (CoreException e) {
1847 } catch (SyntaxError sytaxErr) {
1849 setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
1850 } catch (CoreException e) {
1855 private void statementList() throws CoreException {
1858 if ((token == TT_LISTCLOSE)
1859 || (token == TT_case)
1860 || (token == TT_default)
1861 || (token == TT_elseif)
1862 || (token == TT_endif)
1863 || (token == TT_endfor)
1864 || (token == TT_endforeach)
1865 || (token == TT_endwhile)
1866 || (token == TT_endswitch)
1867 || (token == TT_EOF)
1868 || (token == TT_UNDEFINED)) {
1874 private void compoundStatement() throws CoreException {
1875 // '{' [statement-list] '}'
1876 if (token == TT_LISTOPEN) {
1879 throwSyntaxError("'{' expected in compound-statement.");
1881 if (token != TT_LISTCLOSE) {
1884 if (token == TT_LISTCLOSE) {
1887 throwSyntaxError("'}' expected in compound-statement.");
1891 private void statement() throws CoreException {
1892 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1893 String keyword = identifier;
1894 if (token == TT_include || token == TT_include_once) {
1897 if (token == TT_SEMICOLON) {
1901 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1906 } else if (token == TT_require || token == TT_require_once) {
1910 if (token == TT_SEMICOLON) {
1914 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1919 } else if (token == TT_if) {
1921 if (token == TT_ARGOPEN) {
1924 throwSyntaxError("'(' expected after 'if' keyword.");
1927 if (token == TT_ARGCLOSE) {
1930 throwSyntaxError("')' expected after 'if' condition.");
1935 } else if (token == TT_switch) {
1937 if (token == TT_ARGOPEN) {
1940 throwSyntaxError("'(' expected after 'switch' keyword.");
1943 if (token == TT_ARGCLOSE) {
1946 throwSyntaxError("')' expected after 'switch' condition.");
1950 } else if (token == TT_for) {
1952 if (token == TT_ARGOPEN) {
1955 throwSyntaxError("'(' expected after 'for' keyword.");
1957 if (token == TT_SEMICOLON) {
1961 if (token == TT_SEMICOLON) {
1964 throwSyntaxError("';' expected after 'for'.");
1967 if (token == TT_SEMICOLON) {
1971 if (token == TT_SEMICOLON) {
1974 throwSyntaxError("';' expected after 'for'.");
1977 if (token == TT_ARGCLOSE) {
1981 if (token == TT_ARGCLOSE) {
1984 throwSyntaxError("')' expected after 'for'.");
1989 } else if (token == TT_while) {
1991 if (token == TT_ARGOPEN) {
1994 throwSyntaxError("'(' expected after 'while' keyword.");
1997 if (token == TT_ARGCLOSE) {
2000 throwSyntaxError("')' expected after 'while' condition.");
2004 } else if (token == TT_do) {
2006 if (token == TT_LISTOPEN) {
2009 throwSyntaxError("'{' expected after 'do' keyword.");
2011 if (token != TT_LISTCLOSE) {
2014 if (token == TT_LISTCLOSE) {
2017 throwSyntaxError("'}' expected after 'do' keyword.");
2019 if (token == TT_while) {
2021 if (token == TT_ARGOPEN) {
2024 throwSyntaxError("'(' expected after 'while' keyword.");
2027 if (token == TT_ARGCLOSE) {
2030 throwSyntaxError("')' expected after 'while' condition.");
2033 throwSyntaxError("'while' expected after 'do' keyword.");
2035 if (token == TT_SEMICOLON) {
2039 throwSyntaxError("';' expected after do-while statement.");
2044 } else if (token == TT_foreach) {
2046 if (token == TT_ARGOPEN) {
2049 throwSyntaxError("'(' expected after 'foreach' keyword.");
2052 if (token == TT_as) {
2055 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2058 if (token == TT_FOREACH) {
2062 if (token == TT_ARGCLOSE) {
2065 throwSyntaxError("')' expected after 'foreach' expression.");
2070 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2072 if (token != TT_SEMICOLON) {
2075 if (token == TT_SEMICOLON) {
2079 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2085 } else if (token == TT_echo) {
2088 if (token == TT_SEMICOLON) {
2092 throwSyntaxError("';' expected after 'echo' statement.");
2097 // } else if (token == TT_print) {
2100 // if (token == TT_SEMICOLON) {
2104 // throwSyntaxError("';' expected after 'print' statement.");
2110 } else if (token == TT_global || token == TT_static) {
2113 if (token == TT_SEMICOLON) {
2117 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2123 // } else if (token == TT_unset) {
2125 // if (token == TT_ARGOPEN) {
2128 // throwSyntaxError("'(' expected after 'unset' keyword.");
2131 // if (token == TT_ARGCLOSE) {
2134 // throwSyntaxError("')' expected after 'unset' statement.");
2136 // if (token == TT_SEMICOLON) {
2140 // throwSyntaxError("';' expected after 'unset' statement.");
2146 // } else if (token == TT_exit || token == TT_die) {
2148 // if (token != TT_SEMICOLON) {
2151 // if (token == TT_SEMICOLON) {
2155 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2161 } else if (token == TT_define) {
2163 if (token == TT_ARGOPEN) {
2166 throwSyntaxError("'(' expected after 'define' keyword.");
2169 if (token == TT_COMMA) {
2172 throwSyntaxError("',' expected after first 'define' constant.");
2175 if (token == TT_COMMA) {
2179 if (token == TT_ARGCLOSE) {
2182 throwSyntaxError("')' expected after 'define' statement.");
2184 if (token == TT_SEMICOLON) {
2188 throwSyntaxError("';' expected after 'define' statement.");
2193 } else if (token == TT_function) {
2195 functionDefinition();
2197 } else if (token == TT_class) {
2203 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2204 } else if (token == TT_LISTOPEN) {
2205 // compoundStatement
2207 if (token != TT_LISTCLOSE) {
2210 if (token == TT_LISTCLOSE) {
2214 throwSyntaxError("'}' expected.");
2217 if (token != TT_SEMICOLON) {
2220 if (token == TT_SEMICOLON) {
2225 throwSyntaxError("';' expected after expression.");
2232 private void classDeclarator() throws CoreException {
2234 //identifier 'extends' identifier
2235 if (token == TT_IDENTIFIER) {
2237 if (token == TT_extends) {
2239 if (token == TT_IDENTIFIER) {
2242 throwSyntaxError("Class name expected after keyword 'extends'.");
2246 throwSyntaxError("Class name expected after keyword 'class'.");
2250 private void classBody() throws CoreException {
2251 //'{' [class-element-list] '}'
2252 if (token == TT_LISTOPEN) {
2254 if (token != TT_LISTCLOSE) {
2257 if (token == TT_LISTCLOSE) {
2260 throwSyntaxError("'}' expected at end of class body.");
2263 throwSyntaxError("'{' expected at start of class body.");
2267 private void classElementList() throws CoreException {
2270 } while (token == TT_function || token == TT_var);
2273 private void classElement() throws CoreException {
2275 //function-definition
2276 if (token == TT_function) {
2278 functionDefinition();
2279 } else if (token == TT_var) {
2283 throwSyntaxError("'function' or 'var' expected.");
2287 private void classProperty() throws CoreException {
2288 //'var' variable ';'
2289 //'var' variable '=' constant ';'
2291 if (token == TT_VARIABLE) {
2293 if (token == TT_ASSIGN) {
2298 throwSyntaxError("Variable expected after keyword 'var'.");
2300 if (token != TT_COMMA) {
2305 if (token == TT_SEMICOLON) {
2308 throwSyntaxError("';' expected after variable declaration.");
2312 private void functionDefinition() throws CoreException {
2313 functionDeclarator();
2314 compoundStatement();
2317 private void functionDeclarator() throws CoreException {
2318 //identifier '(' [parameter-list] ')'
2319 if (token == TT_AMPERSAND) {
2322 if (token == TT_IDENTIFIER) {
2324 if (token == TT_ARGOPEN) {
2327 throwSyntaxError("'(' expected in function declaration.");
2329 if (token != TT_ARGCLOSE) {
2332 if (token != TT_ARGCLOSE) {
2333 throwSyntaxError("')' expected in function declaration.");
2340 private void parameterList() throws CoreException {
2341 //parameter-declaration
2342 //parameter-list ',' parameter-declaration
2344 parameterDeclaration();
2345 if (token != TT_COMMA) {
2352 private void parameterDeclaration() throws CoreException {
2354 //variable-reference
2355 if (token == TT_AMPERSAND) {
2357 if (token == TT_VARIABLE) {
2360 throwSyntaxError("Variable expected after reference operator '&'.");
2363 //variable '=' constant
2364 if (token == TT_VARIABLE) {
2366 if (token == TT_ASSIGN) {
2374 private void labeledStatementList() throws CoreException {
2375 if (token != TT_case && token != TT_default) {
2376 throwSyntaxError("'case' or 'default' expected.");
2379 if (token == TT_case) {
2382 if (token == TT_DDOT) {
2384 if (token == TT_case || token == TT_default) { // empty case statement ?
2388 } else if (token == TT_SEMICOLON) {
2389 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2391 if (token == TT_case) { // empty case statement ?
2396 throwSyntaxError("':' character after 'case' constant expected.");
2398 } else { // TT_default
2400 if (token == TT_DDOT) {
2404 throwSyntaxError("':' character after 'default' expected.");
2407 } while (token == TT_case || token == TT_default);
2410 // public void labeledStatement() {
2411 // if (token == TT_case) {
2414 // if (token == TT_DDOT) {
2418 // throwSyntaxError("':' character after 'case' constant expected.");
2421 // } else if (token == TT_default) {
2423 // if (token == TT_DDOT) {
2427 // throwSyntaxError("':' character after 'default' expected.");
2433 // public void expressionStatement() {
2436 // private void inclusionStatement() {
2439 // public void compoundStatement() {
2442 // public void selectionStatement() {
2445 // public void iterationStatement() {
2448 // public void jumpStatement() {
2451 // public void outputStatement() {
2454 // public void scopeStatement() {
2457 // public void flowStatement() {
2460 // public void definitionStatement() {
2463 private void ifStatement() throws CoreException {
2464 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2465 if (token == TT_DDOT) {
2471 if (token == TT_DDOT) {
2475 if (token == TT_if) { //'else if'
2477 elseifStatementList();
2479 throwSyntaxError("':' expected after 'else'.");
2485 elseifStatementList();
2489 if (token != TT_endif) {
2490 throwSyntaxError("'endif' expected.");
2493 if (token != TT_SEMICOLON) {
2494 throwSyntaxError("';' expected after if-statement.");
2498 // statement [else-statement]
2500 if (token == TT_elseif) {
2502 if (token == TT_ARGOPEN) {
2505 throwSyntaxError("'(' expected after 'elseif' keyword.");
2508 if (token == TT_ARGCLOSE) {
2511 throwSyntaxError("')' expected after 'elseif' condition.");
2514 } else if (token == TT_else) {
2521 private void elseifStatementList() throws CoreException {
2527 if (token == TT_DDOT) {
2532 if (token == TT_if) { //'else if'
2535 throwSyntaxError("':' expected after 'else'.");
2548 private void elseifStatement() throws CoreException {
2549 if (token == TT_ARGOPEN) {
2552 if (token != TT_ARGOPEN) {
2553 throwSyntaxError("')' expected in else-if-statement.");
2556 if (token != TT_DDOT) {
2557 throwSyntaxError("':' expected in else-if-statement.");
2564 private void switchStatement() throws CoreException {
2565 if (token == TT_DDOT) {
2566 // ':' [labeled-statement-list] 'endswitch' ';'
2568 labeledStatementList();
2569 if (token != TT_endswitch) {
2570 throwSyntaxError("'endswitch' expected.");
2573 if (token != TT_SEMICOLON) {
2574 throwSyntaxError("';' expected after switch-statement.");
2578 // '{' [labeled-statement-list] '}'
2579 if (token != TT_LISTOPEN) {
2580 throwSyntaxError("'{' expected in switch statement.");
2583 if (token != TT_LISTCLOSE) {
2584 labeledStatementList();
2586 if (token != TT_LISTCLOSE) {
2587 throwSyntaxError("'}' expected in switch statement.");
2594 private void forStatement() throws CoreException {
2595 if (token == TT_DDOT) {
2598 if (token != TT_endfor) {
2599 throwSyntaxError("'endfor' expected.");
2602 if (token != TT_SEMICOLON) {
2603 throwSyntaxError("';' expected after for-statement.");
2611 private void whileStatement() throws CoreException {
2612 // ':' statement-list 'endwhile' ';'
2613 if (token == TT_DDOT) {
2616 if (token != TT_endwhile) {
2617 throwSyntaxError("'endwhile' expected.");
2620 if (token != TT_SEMICOLON) {
2621 throwSyntaxError("';' expected after while-statement.");
2629 private void foreachStatement() throws CoreException {
2630 if (token == TT_DDOT) {
2633 if (token != TT_endforeach) {
2634 throwSyntaxError("'endforeach' expected.");
2637 if (token != TT_SEMICOLON) {
2638 throwSyntaxError("';' expected after foreach-statement.");
2646 private void exitStatus() throws CoreException {
2647 if (token == TT_ARGOPEN) {
2650 throwSyntaxError("'(' expected in 'exit-status'.");
2652 if (token != TT_ARGCLOSE) {
2655 if (token == TT_ARGCLOSE) {
2658 throwSyntaxError("')' expected after 'exit-status'.");
2662 private void expressionList() throws CoreException {
2665 if (token == TT_COMMA) {
2673 private void expression() throws CoreException {
2674 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2677 logicalinclusiveorExpression();
2678 // while (token != TT_SEMICOLON) {
2684 private void postfixExpression() throws CoreException {
2686 boolean castFlag = false;
2701 case TT_STRING_CONSTANT :
2704 case TT_INTERPOLATED_STRING :
2709 if (token == TT_IDENTIFIER) {
2710 // check if identifier is a type:
2712 String str = identifier.toLowerCase();
2713 for (int i = 0; i < PHP_TYPES.length; i++) {
2714 if (PHP_TYPES[i].equals(str)) {
2721 if (token != TT_ARGCLOSE) {
2722 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2732 if (token != TT_ARGCLOSE) {
2733 throwSyntaxError(") expected in postfix-expression.");
2737 case TT_DOUBLE_NUMBER :
2740 case TT_INT_NUMBER :
2743 case TT_DOLLAROPEN :
2746 if (token != TT_LISTCLOSE) {
2747 throwSyntaxError("'}' expected after indirect variable token '${'.");
2754 if (token == TT_LISTOPEN) {
2757 if (token != TT_LISTCLOSE) {
2758 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2761 } else if (token == TT_ARGOPEN) {
2763 if (token != TT_ARGCLOSE) {
2765 if (token != TT_ARGCLOSE) {
2766 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2772 case TT_IDENTIFIER :
2775 if (token == TT_ARGOPEN) {
2777 if (token != TT_ARGCLOSE) {
2779 if (token != TT_ARGCLOSE) {
2780 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2789 // if (token == TT_SEMICOLON) {
2793 // throwSyntaxError("';' expected after 'print' statement.");
2800 if (token == TT_ARGOPEN) {
2802 if (token == TT_COMMA) {
2806 if (token != TT_ARGCLOSE) {
2807 throwSyntaxError("')' expected after 'list' keyword.");
2810 // if (token == TT_SET) {
2812 // logicalinclusiveorExpression();
2815 throwSyntaxError("'(' expected after 'list' keyword.");
2820 // if (token != TT_SEMICOLON) {
2823 // if (token == TT_SEMICOLON) {
2827 // throwSyntaxError("';' expected after 'exit' expression.");
2834 // if (token != TT_SEMICOLON) {
2837 // if (token == TT_SEMICOLON) {
2841 // throwSyntaxError("';' expected after 'die' expression.");
2848 // if (token == TT_ARGOPEN) {
2850 // if (token == TT_COMMA) {
2853 // expressionList();
2854 // if (token != TT_ARGCLOSE) {
2855 // throwSyntaxError("')' expected after 'list' keyword.");
2858 // if (token == TT_SET) {
2860 // logicalinclusiveorExpression();
2863 // throwSyntaxError("'(' expected after 'list' keyword.");
2867 boolean while_flag = true;
2873 if (token != TT_PARTCLOSE) {
2874 throwSyntaxError("] expected in postfix-expression.");
2878 case TT_DDOT2 : // ::
2881 if (token > TT_KEYWORD) {
2883 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2889 // if (token == TT_ARGOPEN) {
2891 // expressionList();
2892 // if (token != TT_ARGCLOSE) {
2893 // throwSyntaxError(") expected after variable '" + ident + "'.");
2898 case TT_IDENTIFIER :
2905 if (token != TT_LISTCLOSE) {
2906 throwSyntaxError("} expected in postfix-expression.");
2911 throwSyntaxError("Syntax error after '->' token.");
2912 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2913 if (token == TT_PARTOPEN) {
2916 if (token != TT_PARTCLOSE) {
2917 throwSyntaxError("] expected after '->'.");
2921 if (token == TT_ARGOPEN) {
2924 if (token != TT_ARGCLOSE) {
2925 throwSyntaxError(") expected after '->'.");
2929 if (token == TT_LISTOPEN) {
2932 if (token != TT_LISTCLOSE) {
2933 throwSyntaxError("} expected after '->'.");
2953 private void unaryExpression() throws CoreException {
2963 // '@' '&' '*' '+' '-' '~' '!'
2993 postfixExpression();
2997 private void castExpression() throws CoreException {
2998 // if (token == TT_ARGOPEN) {
3001 // if (token != TT_ARGCLOSE) {
3002 // throwSyntaxError(") expected after cast-expression.");
3009 private void typeName() throws CoreException {
3010 //'string' 'unset' 'array' 'object'
3012 //'real' 'double' 'float'
3015 if (token == TT_IDENTIFIER) {
3017 String str = identifier.toLowerCase();
3019 for (int i = 0; i < PHP_TYPES.length; i++) {
3020 if (PHP_TYPES[i].equals(str)) {
3025 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3028 private void assignExpression() throws CoreException {
3030 if (token == TT_ASSIGN) { // =
3032 logicalinclusiveorExpression();
3033 } else if (token == TT_DOTASSIGN) { // .=
3035 logicalinclusiveorExpression();
3036 } else if (token == TT_FOREACH) { // =>
3038 logicalinclusiveorExpression();
3039 } else if (token == TT_ADDTO) { // +=
3041 logicalinclusiveorExpression();
3042 } else if (token == TT_SUBTRACTFROM) { // -=
3044 logicalinclusiveorExpression();
3045 } else if (token == TT_TIMESBY) { // *=
3047 logicalinclusiveorExpression();
3048 } else if (token == TT_DIVIDEBY) { // *=
3050 logicalinclusiveorExpression();
3051 } else if (token == TT_MODASSIGN) { // %=
3053 logicalinclusiveorExpression();
3054 } else if (token == TT_ANDASSIGN) { // &=
3056 logicalinclusiveorExpression();
3057 } else if (token == TT_POWASSIGN) { // ^=
3059 logicalinclusiveorExpression();
3060 } else if (token == TT_LSHIFTASSIGN) { // <<=
3062 logicalinclusiveorExpression();
3063 } else if (token == TT_RSHIFTASSIGN) { // >>=
3065 logicalinclusiveorExpression();
3066 } else if (token == TT_TILDEASSIGN) { // ~=
3068 logicalinclusiveorExpression();
3072 private void multiplicativeExpression() throws CoreException {
3075 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3082 private void concatenationExpression() throws CoreException {
3084 multiplicativeExpression();
3085 if (token != TT_DOT) {
3092 private void additiveExpression() throws CoreException {
3094 concatenationExpression();
3095 if (token != TT_ADD && token != TT_SUBTRACT) {
3102 private void shiftExpression() throws CoreException {
3104 additiveExpression();
3105 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3112 private void relationalExpression() throws CoreException {
3115 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3122 private void identicalExpression() throws CoreException {
3124 relationalExpression();
3125 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3132 private void equalityExpression() throws CoreException {
3134 identicalExpression();
3135 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3142 private void ternaryExpression() throws CoreException {
3143 equalityExpression();
3144 if (token == TT_QUESTIONMARK) {
3147 if (token == TT_DDOT) {
3151 throwSyntaxError("':' expected in ternary operator '? :'.");
3156 private void andExpression() throws CoreException {
3158 ternaryExpression();
3159 if (token != TT_AMPERSAND) {
3166 private void exclusiveorExpression() throws CoreException {
3169 if (token != TT_POW) {
3176 private void inclusiveorExpression() throws CoreException {
3178 exclusiveorExpression();
3179 if (token != TT_LINE) {
3186 private void booleanandExpression() throws CoreException {
3188 inclusiveorExpression();
3189 if (token != TT_AND) {
3196 private void booleanorExpression() throws CoreException {
3198 booleanandExpression();
3199 if (token != TT_OR) {
3206 private void logicalandExpression() throws CoreException {
3208 booleanorExpression();
3209 if (token != TT_and) {
3216 private void logicalexclusiveorExpression() throws CoreException {
3218 logicalandExpression();
3219 if (token != TT_xor) {
3226 private void logicalinclusiveorExpression() throws CoreException {
3228 logicalexclusiveorExpression();
3229 if (token != TT_or) {
3236 // public void assignmentExpression() {
3237 // if (token == TT_VARIABLE) {
3239 // if (token == TT_SET) {
3241 // logicalinclusiveorExpression();
3244 // logicalinclusiveorExpression();
3248 private void variableList() throws CoreException {
3251 if (token == TT_COMMA) {
3259 private void variable() throws CoreException {
3260 if (token == TT_DOLLAROPEN) {
3264 if (token != TT_LISTCLOSE) {
3265 throwSyntaxError("'}' expected after indirect variable token '${'.");
3269 if (token == TT_VARIABLE) {
3271 if (token == TT_PARTOPEN) {
3274 if (token != TT_PARTCLOSE) {
3275 throwSyntaxError("']' expected in variable-list.");
3278 } else if (token == TT_ASSIGN) {
3283 throwSyntaxError("$-variable expected in variable-list.");
3288 private void constant() throws CoreException {
3294 case TT_DOUBLE_NUMBER :
3297 case TT_INT_NUMBER :
3301 throwSyntaxError("Constant expected after '+' presign.");
3307 case TT_DOUBLE_NUMBER :
3310 case TT_INT_NUMBER :
3314 throwSyntaxError("Constant expected after '-' presign.");
3326 case TT_IDENTIFIER :
3329 if (token == TT_ARGOPEN) {
3331 if (token != TT_ARGCLOSE) {
3333 if (token != TT_ARGCLOSE) {
3334 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3340 case TT_STRING_CONSTANT :
3343 case TT_INTERPOLATED_STRING :
3346 case TT_DOUBLE_NUMBER :
3349 case TT_INT_NUMBER :
3353 throwSyntaxError("Constant expected.");
3358 * Call the php parse command ( php -l -f <filename> )
3359 * and create markers according to the external parser output
3361 public static void phpExternalParse(IFile file) {
3362 //IFile file = (IFile) resource;
3363 IPath path = file.getFullPath();
3364 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3365 String filename = file.getLocation().toString();
3367 String[] arguments = { filename };
3368 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3369 String command = form.format(arguments);
3371 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3374 // parse the buffer to find the errors and warnings
3375 createMarkers(parserResult, file);
3376 } catch (CoreException e) {
3381 * Create markers according to the external parser output
3383 private static void createMarkers(String output, IFile file) throws CoreException {
3384 // delete all markers
3385 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3389 boolean flag = true;
3390 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3391 // newer php error output (tested with 4.2.3)
3392 scanLine(output, file, indx, brIndx);
3397 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3398 // older php error output (tested with 4.2.3)
3399 scanLine(output, file, indx, brIndx);
3405 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3407 String outLineNumberString;
3408 StringBuffer lineNumberBuffer = new StringBuffer(10);
3410 current = output.substring(indx, brIndx);
3412 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3413 int onLine = current.indexOf("on line <b>");
3415 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3416 for (int i = onLine; i < current.length(); i++) {
3417 ch = current.charAt(i);
3418 if ('0' <= ch && '9' >= ch) {
3419 lineNumberBuffer.append(ch);
3423 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3425 Hashtable attributes = new Hashtable();
3427 current = current.replaceAll("\n", "");
3428 current = current.replaceAll("<b>", "");
3429 current = current.replaceAll("</b>", "");
3430 MarkerUtilities.setMessage(attributes, current);
3432 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3433 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3434 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3435 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3437 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3438 MarkerUtilities.setLineNumber(attributes, lineNumber);
3439 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);