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;
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:
65 private String stringValue;
67 /** Contains the current expression. */
68 private StringBuffer expression;
70 private boolean phpMode;
72 final static int TT_EOF = 0;
73 final static int TT_UNDEFINED = 1;
74 final static int TT_HTML = 2;
76 final static int TT_MOD = 30;
77 final static int TT_NOT = 31;
78 final static int TT_DOT = 32;
79 final static int TT_POW = 33;
80 final static int TT_DIV = 34;
81 final static int TT_MULTIPLY = 35;
82 final static int TT_SUBTRACT = 36;
83 final static int TT_ADD = 37;
84 final static int TT_EQUAL = 38;
85 final static int TT_UNEQUAL = 39;
86 final static int TT_GREATER = 40;
87 final static int TT_GREATEREQUAL = 41;
88 final static int TT_LESS = 42;
89 final static int TT_LESSEQUAL = 43;
90 final static int TT_AND = 44;
91 final static int TT_OR = 45;
92 final static int TT_HASH = 46;
93 final static int TT_DDOT = 47;
94 final static int TT_DOTASSIGN = 48;
96 final static int TT_ASSIGN = 49;
97 final static int TT_REF = 50;
98 final static int TT_FOREACH = 51;
99 final static int TT_AMPERSAND = 52;
100 final static int TT_DOLLARLISTOPEN = 53;
101 final static int TT_TILDE = 54;
102 final static int TT_TILDEASSIGN = 55;
103 final static int TT_MODASSIGN = 56;
104 final static int TT_POWASSIGN = 57;
105 final static int TT_RSHIFTASSIGN = 58;
106 final static int TT_LSHIFTASSIGN = 59;
107 final static int TT_ANDASSIGN = 60;
108 final static int TT_QUESTIONMARK = 61;
109 final static int TT_DDOT2 = 62;
110 final static int TT_AT = 63;
111 // final static int TT_HEREDOC = 64;
113 final static int TT_DOLLAROPEN = 127;
114 final static int TT_ARGOPEN = 128;
115 final static int TT_ARGCLOSE = 129;
116 final static int TT_LISTOPEN = 130;
117 final static int TT_LISTCLOSE = 131;
118 final static int TT_PARTOPEN = 132;
119 final static int TT_PARTCLOSE = 133;
120 final static int TT_COMMA = 134;
122 final static int TT_STRING = 136;
123 final static int TT_IDENTIFIER = 138;
124 final static int TT_DIGIT = 139;
125 final static int TT_SEMICOLON = 140;
126 final static int TT_SLOT = 141;
127 final static int TT_SLOTSEQUENCE = 142;
128 final static int TT_DECREMENT = 144;
129 final static int TT_INCREMENT = 145;
130 final static int TT_ADDTO = 146;
131 final static int TT_DIVIDEBY = 147;
132 final static int TT_SUBTRACTFROM = 148;
133 final static int TT_TIMESBY = 149;
134 final static int TT_VARIABLE = 150;
135 final static int TT_INT_NUMBER = 151;
136 final static int TT_DOUBLE_NUMBER = 152;
137 final static int TT_INTERPOLATED_STRING = 153;
138 final static int TT_STRING_CONSTANT = 154;
140 final static int TT_LSHIFT = 155;
141 final static int TT_RSHIFT = 156;
142 final static int TT_EX_EQUAL = 157;
143 final static int TT_EX_UNEQUAL = 158;
144 final static int TT_LINE = 159;
145 // final static int TT_AT = 153; // @
150 *@param sess Description of Parameter
153 public PHPParser(IFile fileToParse) {
154 if (keywordMap == null) {
155 keywordMap = new HashMap();
156 for (int i = 0; i < PHP_KEYWORS.length; i++) {
157 keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
160 this.currentPHPString = 0;
161 this.fileToParse = fileToParse;
167 this.columnCount = 0;
174 * Create marker for the parse error
176 private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
177 setMarker(fileToParse, message, lineNumber, errorLevel);
180 public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
182 Hashtable attributes = new Hashtable();
183 MarkerUtilities.setMessage(attributes, message);
184 switch (errorLevel) {
186 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
189 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
192 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
195 MarkerUtilities.setLineNumber(attributes, lineNumber);
196 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
200 private void throwSyntaxError(String error) {
202 if (str.length() < chIndx) {
205 // read until end-of-line
207 while (str.length() > eol) {
208 ch = str.charAt(eol++);
214 throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
217 private void throwSyntaxError(String error, int startRow) {
219 throw new SyntaxError(startRow, 0, " ", error);
223 * Method Declaration.
227 private void getChar() {
228 if (str.length() > chIndx) {
229 ch = str.charAt(chIndx++);
234 chIndx = str.length() + 1;
240 private void getNextToken_OldVersion() throws CoreException {
243 while (str.length() > chIndx) {
244 ch = str.charAt(chIndx++);
245 token = TT_UNDEFINED;
248 columnCount = chIndx;
249 continue; // while loop
251 if (str.length() == chIndx) {
254 if (!Character.isWhitespace(ch)) {
256 if (str.length() > chIndx) {
257 if (str.charAt(chIndx) == '{') {
259 token = TT_DOLLAROPEN;
266 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
270 if (ch >= '0' && ch <= '9') {
275 if (str.length() > chIndx) {
276 if (str.charAt(chIndx) == '/') {
278 // read comment until end of line:
279 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
283 } else if (str.charAt(chIndx) == '*') {
285 // multi line comment:
286 while (str.length() > chIndx) {
287 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
291 ch = str.charAt(chIndx++);
294 columnCount = chIndx;
300 } else if (ch == '#') {
301 // read comment until end of line:
302 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
306 } else if (ch == '"') {
307 // read string until end
308 boolean openString = true;
309 while (str.length() > chIndx) {
310 ch = str.charAt(chIndx++);
312 if (str.length() > chIndx) {
313 ch = str.charAt(chIndx++);
315 } else if (ch == '"') {
318 } else if (ch == '\n') {
320 columnCount = chIndx;
324 throwSyntaxError("Open string character '\"' at end of file.");
326 token = TT_INTERPOLATED_STRING;
328 } else if (ch == '\'') {
329 // read string until end
330 boolean openString = true;
331 int startRow = rowCount;
332 while (str.length() > chIndx) {
333 ch = str.charAt(chIndx++);
335 if (str.length() > chIndx) {
336 ch = str.charAt(chIndx++);
338 } else if (ch == '\'') {
341 } else if (ch == '\n') {
343 columnCount = chIndx;
347 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
349 token = TT_STRING_CONSTANT;
351 } else if (ch == '`') {
352 // read string until end
353 boolean openString = true;
354 int startRow = rowCount;
355 while (str.length() > chIndx) {
356 ch = str.charAt(chIndx++);
358 if (str.length() > chIndx) {
359 ch = str.charAt(chIndx++);
361 } else if (ch == '`') {
364 } else if (ch == '\n') {
366 columnCount = chIndx;
370 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
372 token = TT_STRING_CONSTANT;
391 token = TT_LISTCLOSE;
399 token = TT_PARTCLOSE;
407 token = TT_QUESTIONMARK;
414 if (str.length() > chIndx) {
415 if (str.charAt(chIndx) == '=') {
417 token = TT_TILDEASSIGN;
425 if (str.length() > chIndx) {
426 if (str.charAt(chIndx) == '=') {
428 token = TT_DOTASSIGN;
441 if (str.length() > chIndx) {
442 if (str.charAt(chIndx) == '=') {
444 token = TT_MODASSIGN;
451 token = TT_SEMICOLON;
456 if (str.length() > chIndx) {
457 if (str.charAt(chIndx) == '=') {
459 token = TT_POWASSIGN;
468 if (str.length() > chIndx) {
469 if (str.charAt(chIndx) == '=') {
480 if (str.length() > chIndx) {
481 if (str.charAt(chIndx) == '*') {
487 if (str.charAt(chIndx) == '=') {
498 if (str.length() > chIndx) {
499 if (str.charAt(chIndx) == '+') {
501 token = TT_INCREMENT;
505 if (str.charAt(chIndx) == '=') {
515 if (str.length() > chIndx) {
516 if (str.charAt(chIndx) == '-') {
518 token = TT_DECREMENT;
522 if (str.charAt(chIndx) == '=') {
524 token = TT_SUBTRACTFROM;
528 if (str.charAt(chIndx) == '>') {
540 if (str.length() > chIndx) {
541 ch = str.charAt(chIndx);
546 if (str.length() > chIndx) {
547 ch = str.charAt(chIndx);
568 if (str.length() > chIndx) {
569 if (str.charAt(chIndx) == '=') {
572 if (str.length() > chIndx) {
573 ch = str.charAt(chIndx);
577 token = TT_EX_UNEQUAL;
588 if (str.length() > chIndx) {
589 if (str.charAt(chIndx) == '=') {
591 token = TT_GREATEREQUAL;
594 if (str.charAt(chIndx) == '>') {
597 if (str.length() > chIndx) {
598 if (str.charAt(chIndx) == '=') {
600 token = TT_RSHIFTASSIGN;
612 if (str.length() > chIndx) {
613 if (str.charAt(chIndx) == '=') {
615 token = TT_LESSEQUAL;
619 if (str.charAt(chIndx) == '<') {
622 if (str.charAt(chIndx) == '<') {
624 int startRow = rowCount;
625 if (str.length() > chIndx) {
627 ch = str.charAt(++chIndx);
628 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
631 token = TT_STRING_CONSTANT;
632 while (str.length() > chIndx) {
633 ch = str.charAt(chIndx++);
635 if (str.length() >= chIndx + identifier.length()) {
636 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
637 chIndx += identifier.length();
645 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
646 } else if (str.charAt(chIndx) == '=') {
648 token = TT_LSHIFTASSIGN;
660 if (str.length() > chIndx) {
661 if (str.charAt(chIndx) == '|') {
671 token = TT_AMPERSAND;
672 if (str.length() > chIndx) {
673 if (str.charAt(chIndx) == '&') {
678 if (str.charAt(chIndx) == '=') {
680 token = TT_ANDASSIGN;
689 if (str.length() > chIndx) {
690 if (str.charAt(chIndx) == ':') {
705 throwSyntaxError("unexpected character: '" + ch + "'");
708 if (token == TT_UNDEFINED) {
709 throwSyntaxError("token not found");
716 chIndx = str.length() + 1;
721 if (phpList != null) {
722 if (currentPHPString < phpList.size()) {
723 token = TT_UNDEFINED;
724 temp = (PHPString) phpList.get(currentPHPString++);
725 this.str = temp.getPHPString();
728 this.rowCount = temp.getLineNumber();
729 this.columnCount = 0;
733 token = TT_UNDEFINED;
739 * gets the next token from input
741 private void getNextToken() throws CoreException {
742 boolean phpFound = false;
749 while (str.length() > chIndx) {
750 token = TT_UNDEFINED;
751 ch = str.charAt(chIndx++);
757 ch2 = str.charAt(chIndx++);
759 ch2 = str.charAt(chIndx++);
760 if (Character.isWhitespace(ch2)) {
765 } else if (ch2 == 'p' || ch2 == 'P') {
766 ch2 = str.charAt(chIndx++);
767 if (ch2 == 'h' || ch2 == 'H') {
768 ch2 = str.charAt(chIndx++);
769 if (ch2 == 'p' || ch2 == 'P') {
787 while (str.length() > chIndx) {
788 ch = str.charAt(chIndx++);
789 token = TT_UNDEFINED;
792 columnCount = chIndx;
793 continue; // while loop
795 if (str.length() == chIndx) {
798 if (!Character.isWhitespace(ch)) {
800 if (str.length() > chIndx) {
801 if (str.charAt(chIndx) == '{') {
803 token = TT_DOLLAROPEN;
810 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
814 if (ch >= '0' && ch <= '9') {
819 if (str.length() > chIndx) {
820 if (str.charAt(chIndx) == '/') {
823 // read comment until end of line:
824 while ((str.length() > chIndx) && (ch != '\n')) {
825 ch = str.charAt(chIndx++);
827 ch2 = str.charAt(chIndx);
841 } else if (str.charAt(chIndx) == '*') {
843 // multi line comment:
844 while (str.length() > chIndx) {
845 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
849 ch = str.charAt(chIndx++);
852 columnCount = chIndx;
858 } else if (ch == '#') {
859 // read comment until end of line:
860 while ((str.length() > chIndx) && (ch != '\n')) {
861 ch = str.charAt(chIndx++);
863 ch2 = str.charAt(chIndx);
877 } else if (ch == '"') {
878 getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
880 } else if (ch == '\'') {
881 getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
883 } else if (ch == '`') {
884 getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
885 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
904 token = TT_LISTCLOSE;
912 token = TT_PARTCLOSE;
920 token = TT_QUESTIONMARK;
921 if (str.length() > chIndx) {
922 if (str.charAt(chIndx) == '>') {
938 if (str.length() > chIndx) {
939 if (str.charAt(chIndx) == '=') {
941 token = TT_TILDEASSIGN;
949 if (str.length() > chIndx) {
950 if (str.charAt(chIndx) == '=') {
952 token = TT_DOTASSIGN;
965 if (str.length() > chIndx) {
966 if (str.charAt(chIndx) == '=') {
968 token = TT_MODASSIGN;
975 token = TT_SEMICOLON;
980 if (str.length() > chIndx) {
981 if (str.charAt(chIndx) == '=') {
983 token = TT_POWASSIGN;
992 if (str.length() > chIndx) {
993 if (str.charAt(chIndx) == '=') {
1003 token = TT_MULTIPLY;
1004 if (str.length() > chIndx) {
1005 if (str.charAt(chIndx) == '*') {
1011 if (str.charAt(chIndx) == '=') {
1022 if (str.length() > chIndx) {
1023 if (str.charAt(chIndx) == '+') {
1025 token = TT_INCREMENT;
1029 if (str.charAt(chIndx) == '=') {
1038 token = TT_SUBTRACT;
1039 if (str.length() > chIndx) {
1040 if (str.charAt(chIndx) == '-') {
1042 token = TT_DECREMENT;
1046 if (str.charAt(chIndx) == '=') {
1048 token = TT_SUBTRACTFROM;
1052 if (str.charAt(chIndx) == '>') {
1064 if (str.length() > chIndx) {
1065 ch = str.charAt(chIndx);
1070 if (str.length() > chIndx) {
1071 ch = str.charAt(chIndx);
1075 token = TT_EX_EQUAL;
1092 if (str.length() > chIndx) {
1093 if (str.charAt(chIndx) == '=') {
1096 if (str.length() > chIndx) {
1097 ch = str.charAt(chIndx);
1101 token = TT_EX_UNEQUAL;
1112 if (str.length() > chIndx) {
1113 if (str.charAt(chIndx) == '=') {
1115 token = TT_GREATEREQUAL;
1118 if (str.charAt(chIndx) == '>') {
1121 if (str.length() > chIndx) {
1122 if (str.charAt(chIndx) == '=') {
1124 token = TT_RSHIFTASSIGN;
1136 if (str.length() > chIndx) {
1137 if (str.charAt(chIndx) == '=') {
1139 token = TT_LESSEQUAL;
1143 if (str.charAt(chIndx) == '<') {
1146 if (str.charAt(chIndx) == '<') {
1148 int startRow = rowCount;
1149 if (str.length() > chIndx) {
1151 ch = str.charAt(++chIndx);
1152 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1155 token = TT_STRING_CONSTANT;
1156 while (str.length() > chIndx) {
1157 ch = str.charAt(chIndx++);
1159 if (str.length() >= chIndx + identifier.length()) {
1160 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1161 chIndx += identifier.length();
1169 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1170 } else if (str.charAt(chIndx) == '=') {
1172 token = TT_LSHIFTASSIGN;
1184 if (str.length() > chIndx) {
1185 if (str.charAt(chIndx) == '|') {
1195 token = TT_AMPERSAND;
1196 if (str.length() > chIndx) {
1197 if (str.charAt(chIndx) == '&') {
1202 if (str.charAt(chIndx) == '=') {
1204 token = TT_ANDASSIGN;
1213 if (str.length() > chIndx) {
1214 if (str.charAt(chIndx) == ':') {
1229 throwSyntaxError("unexpected character: '" + ch + "'");
1232 if (token == TT_UNDEFINED) {
1233 throwSyntaxError("token not found");
1240 } catch (StringIndexOutOfBoundsException e) {
1241 // catched from charAt
1244 chIndx = str.length() + 1;
1249 // if (phpList != null) {
1250 // if (currentPHPString < phpList.size()) {
1251 // token = TT_UNDEFINED;
1252 // temp = (PHPString) phpList.get(currentPHPString++);
1253 // this.str = temp.getPHPString();
1254 // this.token = TT_EOF;
1256 // this.rowCount = temp.getLineNumber();
1257 // this.columnCount = 0;
1261 // token = TT_UNDEFINED;
1268 private void getIdentifier() {
1269 // StringBuffer ident = new StringBuffer();
1270 int startPosition = chIndx - 1;
1271 // ident.append(ch);
1274 // attention recursive call:
1276 token = TT_VARIABLE;
1279 token = TT_IDENTIFIER;
1283 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1284 // ident.append(ch);
1287 int endPosition = chIndx--;
1288 int length = (--endPosition) - startPosition;
1290 identifier = str.substring(startPosition, endPosition);
1291 // System.out.println(identifier);
1293 // determine if this identitfer is a keyword
1294 // @todo improve this in future version
1295 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1297 token = i.intValue();
1301 private void getNumber() {
1302 StringBuffer inum = new StringBuffer();
1311 // determine number conversions:
1312 if (firstCh == '0') {
1341 if (numFormat == 16) {
1342 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1347 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1348 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1349 if (ch == '.' && dFlag != ' ') {
1352 if ((dFlag == 'E') || (dFlag == 'e')) {
1358 if ((ch == '-') || (ch == '+')) {
1372 doubleNumber = new Double(inum.toString());
1373 token = TT_DOUBLE_NUMBER;
1376 longNumber = Long.valueOf(inum.toString(), numFormat);
1377 token = TT_INT_NUMBER;
1381 } catch (Throwable e) {
1382 throwSyntaxError("Number format error: " + inum.toString());
1388 * @param openChar the opening char ('\'', '"', '`')
1389 * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
1390 * @param errorMsg the error message in case of parse error in the string
1392 private void getString(final char openChar, final int typeString, final String errorMsg) {
1393 StringBuffer sBuffer = new StringBuffer();
1394 boolean openString = true;
1395 int startRow = rowCount;
1396 while (str.length() > chIndx) {
1397 ch = str.charAt(chIndx++);
1400 if (str.length() > chIndx) {
1401 ch = str.charAt(chIndx++);
1404 } else if (ch == openChar) {
1407 } else if (ch == '\n') {
1409 columnCount = chIndx;
1415 if (typeString == TT_STRING_CONSTANT) {
1416 throwSyntaxError(errorMsg, startRow);
1418 throwSyntaxError(errorMsg);
1422 stringValue = sBuffer.toString();
1425 public void htmlParserTester(String input) {
1427 int startLineNumber = 1;
1431 boolean phpMode = false;
1432 boolean phpFound = false;
1434 phpList = new ArrayList();
1435 currentPHPString = 0;
1439 while (i < input.length()) {
1440 ch = input.charAt(i++);
1444 if ((!phpMode) && ch == '<') {
1445 ch2 = input.charAt(i++);
1447 ch2 = input.charAt(i++);
1448 if (Character.isWhitespace(ch2)) {
1453 startLineNumber = lineNumber;
1455 } else if (ch2 == 'p') {
1456 ch2 = input.charAt(i++);
1458 ch2 = input.charAt(i++);
1463 startLineNumber = lineNumber;
1469 } else if (ch2 == 'P') {
1470 ch2 = input.charAt(i++);
1472 ch2 = input.charAt(i++);
1477 startLineNumber = lineNumber;
1490 if (ch == '/' && i < input.length()) {
1491 ch2 = input.charAt(i++);
1493 while (i < input.length()) {
1494 ch = input.charAt(i++);
1495 if (ch == '?' && i < input.length()) {
1496 ch2 = input.charAt(i++);
1500 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1504 } else if (ch == '\n') {
1510 } else if (ch2 == '*') {
1511 // multi-line comment
1512 while (i < input.length()) {
1513 ch = input.charAt(i++);
1516 } else if (ch == '*' && i < input.length()) {
1517 ch2 = input.charAt(i++);
1528 } else if (ch == '#') {
1529 while (i < input.length()) {
1530 ch = input.charAt(i++);
1531 if (ch == '?' && i < input.length()) {
1532 ch2 = input.charAt(i++);
1536 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1540 } else if (ch == '\n') {
1546 } else if (ch == '"') {
1548 while (i < input.length()) {
1549 ch = input.charAt(i++);
1552 } else if (ch == '\\' && i < input.length()) { // escape
1554 } else if (ch == '"') {
1559 } else if (ch == '\'') {
1561 while (i < input.length()) {
1562 ch = input.charAt(i++);
1565 } else if (ch == '\\' && i < input.length()) { // escape
1567 } else if (ch == '\'') {
1574 if (ch == '?' && i < input.length()) {
1575 ch2 = input.charAt(i++);
1579 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1588 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1591 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1592 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1594 // for (int j=0;j<phpList.size();j++) {
1595 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1596 // int startIndx = temp.length()-10;
1597 // if (startIndx<0) {
1600 // System.out.println(temp.substring(startIndx)+"?>");
1602 phpParserTester(null, 1);
1604 // for(int j=0;j<phpList.size();j++) {
1605 // temp = (PHPString) phpList.get(j);
1606 // parser.start(temp.getPHPString(), temp.getLineNumber());
1609 } catch (CoreException e) {
1613 public void phpParserTester(String s, int rowCount) throws CoreException {
1616 if (phpList.size() != 0) {
1617 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1620 this.token = TT_EOF;
1622 this.rowCount = rowCount;
1623 this.columnCount = 0;
1624 this.phpEnd = false;
1625 this.phpMode = true;
1629 if (token != TT_EOF && token != TT_UNDEFINED) {
1632 if (token != TT_EOF && token != TT_UNDEFINED) {
1633 if (token == TT_ARGCLOSE) {
1634 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1636 if (token == TT_LISTCLOSE) {
1637 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1639 if (token == TT_PARTCLOSE) {
1640 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1643 if (token == TT_ARGOPEN) {
1644 throwSyntaxError("Read character '('; end-of-file not reached.");
1646 if (token == TT_LISTOPEN) {
1647 throwSyntaxError("Read character '{'; end-of-file not reached.");
1649 if (token == TT_PARTOPEN) {
1650 throwSyntaxError("Read character '['; end-of-file not reached.");
1653 throwSyntaxError("End-of-file not reached.");
1656 } catch (SyntaxError err) {
1660 setMarker(err.getMessage(), err.getLine(), ERROR);
1662 // if an error occured,
1663 // try to find keywords 'class' or 'function'
1664 // to parse the rest of the string
1665 while (token != TT_EOF && token != TT_UNDEFINED) {
1666 if (token == TT_class || token == TT_function) {
1671 if (token == TT_EOF || token == TT_UNDEFINED) {
1680 * Parses a string with php tags
1681 * i.e. '<body> <?php phpinfo() ?> </body>'
1683 public void parse(String s) throws CoreException {
1685 this.token = TT_EOF;
1688 this.columnCount = 0;
1689 this.phpEnd = false;
1690 this.phpMode = false;
1694 if (token != TT_EOF && token != TT_UNDEFINED) {
1697 if (token != TT_EOF && token != TT_UNDEFINED) {
1698 if (token == TT_ARGCLOSE) {
1699 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1701 if (token == TT_LISTCLOSE) {
1702 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1704 if (token == TT_PARTCLOSE) {
1705 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1708 if (token == TT_ARGOPEN) {
1709 throwSyntaxError("Read character '('; end-of-file not reached.");
1711 if (token == TT_LISTOPEN) {
1712 throwSyntaxError("Read character '{'; end-of-file not reached.");
1714 if (token == TT_PARTOPEN) {
1715 throwSyntaxError("Read character '['; end-of-file not reached.");
1718 throwSyntaxError("End-of-file not reached.");
1721 } catch (SyntaxError sytaxErr1) {
1722 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1724 // if an error occured,
1725 // try to find keywords 'class' or 'function'
1726 // to parse the rest of the string
1727 while (token != TT_EOF && token != TT_UNDEFINED) {
1728 if (token == TT_class || token == TT_function) {
1733 if (token == TT_EOF || token == TT_UNDEFINED) {
1736 } catch (SyntaxError sytaxErr2) {
1737 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1745 public PHPOutlineInfo parseInfo(Object parent, String s) {
1746 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1747 // Stack stack = new Stack();
1748 // stack.push(outlineInfo.getDeclarations());
1751 this.token = TT_EOF;
1754 this.columnCount = 0;
1755 this.phpEnd = false;
1756 this.phpMode = false;
1760 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1761 } catch (CoreException e) {
1766 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
1767 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1768 PHPSegmentWithChildren temp;
1770 String oldIdentifier;
1771 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1773 while (token != TT_EOF && token != TT_UNDEFINED) {
1774 if (token == TT_VARIABLE) {
1775 outlineInfo.addVariable(identifier);
1777 } else if (token == TT_var) {
1779 if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1781 outlineInfo.addVariable(identifier);
1782 if (token != TT_SEMICOLON) {
1783 oldIdentifier = identifier;
1786 case TT_VARIABLE : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1788 case TT_IDENTIFIER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1790 case TT_DOUBLE_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
1792 case TT_INT_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
1794 case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1796 case TT_STRING_CONSTANT : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1798 default : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
1802 current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1805 } else if (token == TT_function) {
1807 if (token == TT_AMPERSAND) {
1810 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1811 outlineInfo.addVariable(identifier);
1812 temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
1815 parseDeclarations(outlineInfo, temp, true);
1817 } else if (token == TT_class) {
1819 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
1820 outlineInfo.addVariable(identifier);
1821 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1823 // stack.push(temp);
1826 //skip tokens for classname, extends and others until we have the opening '{'
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) {
1842 } else if (token == TT_require || token == TT_require_once || token == TT_include || token == TT_include_once) {
1844 outlineInfo.addVariable(identifier);
1845 current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
1851 } catch (CoreException e) {
1852 } catch (SyntaxError sytaxErr) {
1854 setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
1855 } catch (CoreException e) {
1860 private void statementList() throws CoreException {
1863 if ((token == TT_LISTCLOSE)
1864 || (token == TT_case)
1865 || (token == TT_default)
1866 || (token == TT_elseif)
1867 || (token == TT_endif)
1868 || (token == TT_endfor)
1869 || (token == TT_endforeach)
1870 || (token == TT_endwhile)
1871 || (token == TT_endswitch)
1872 || (token == TT_EOF)
1873 || (token == TT_UNDEFINED)) {
1879 private void compoundStatement() throws CoreException {
1880 // '{' [statement-list] '}'
1881 if (token == TT_LISTOPEN) {
1884 throwSyntaxError("'{' expected in compound-statement.");
1886 if (token != TT_LISTCLOSE) {
1889 if (token == TT_LISTCLOSE) {
1892 throwSyntaxError("'}' expected in compound-statement.");
1896 private void statement() throws CoreException {
1897 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1898 String keyword = identifier;
1899 if (token == TT_include || token == TT_include_once) {
1902 if (token == TT_SEMICOLON) {
1906 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1911 } else if (token == TT_require || token == TT_require_once) {
1915 if (token == TT_SEMICOLON) {
1919 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1924 } else if (token == TT_if) {
1926 if (token == TT_ARGOPEN) {
1929 throwSyntaxError("'(' expected after 'if' keyword.");
1932 if (token == TT_ARGCLOSE) {
1935 throwSyntaxError("')' expected after 'if' condition.");
1940 } else if (token == TT_switch) {
1942 if (token == TT_ARGOPEN) {
1945 throwSyntaxError("'(' expected after 'switch' keyword.");
1948 if (token == TT_ARGCLOSE) {
1951 throwSyntaxError("')' expected after 'switch' condition.");
1955 } else if (token == TT_for) {
1957 if (token == TT_ARGOPEN) {
1960 throwSyntaxError("'(' expected after 'for' keyword.");
1962 if (token == TT_SEMICOLON) {
1966 if (token == TT_SEMICOLON) {
1969 throwSyntaxError("';' expected after 'for'.");
1972 if (token == TT_SEMICOLON) {
1976 if (token == TT_SEMICOLON) {
1979 throwSyntaxError("';' expected after 'for'.");
1982 if (token == TT_ARGCLOSE) {
1986 if (token == TT_ARGCLOSE) {
1989 throwSyntaxError("')' expected after 'for'.");
1994 } else 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.");
2009 } else if (token == TT_do) {
2011 if (token == TT_LISTOPEN) {
2014 throwSyntaxError("'{' expected after 'do' keyword.");
2016 if (token != TT_LISTCLOSE) {
2019 if (token == TT_LISTCLOSE) {
2022 throwSyntaxError("'}' expected after 'do' keyword.");
2024 if (token == TT_while) {
2026 if (token == TT_ARGOPEN) {
2029 throwSyntaxError("'(' expected after 'while' keyword.");
2032 if (token == TT_ARGCLOSE) {
2035 throwSyntaxError("')' expected after 'while' condition.");
2038 throwSyntaxError("'while' expected after 'do' keyword.");
2040 if (token == TT_SEMICOLON) {
2044 throwSyntaxError("';' expected after do-while statement.");
2049 } else if (token == TT_foreach) {
2051 if (token == TT_ARGOPEN) {
2054 throwSyntaxError("'(' expected after 'foreach' keyword.");
2057 if (token == TT_as) {
2060 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2063 if (token == TT_FOREACH) {
2067 if (token == TT_ARGCLOSE) {
2070 throwSyntaxError("')' expected after 'foreach' expression.");
2075 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2077 if (token != TT_SEMICOLON) {
2080 if (token == TT_SEMICOLON) {
2084 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2090 } else if (token == TT_echo) {
2093 if (token == TT_SEMICOLON) {
2097 throwSyntaxError("';' expected after 'echo' statement.");
2102 // } else if (token == TT_print) {
2105 // if (token == TT_SEMICOLON) {
2109 // throwSyntaxError("';' expected after 'print' statement.");
2115 } else if (token == TT_global || token == TT_static) {
2118 if (token == TT_SEMICOLON) {
2122 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2128 // } else if (token == TT_unset) {
2130 // if (token == TT_ARGOPEN) {
2133 // throwSyntaxError("'(' expected after 'unset' keyword.");
2136 // if (token == TT_ARGCLOSE) {
2139 // throwSyntaxError("')' expected after 'unset' statement.");
2141 // if (token == TT_SEMICOLON) {
2145 // throwSyntaxError("';' expected after 'unset' statement.");
2151 // } else if (token == TT_exit || token == TT_die) {
2153 // if (token != TT_SEMICOLON) {
2156 // if (token == TT_SEMICOLON) {
2160 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2166 } else if (token == TT_define) {
2168 if (token == TT_ARGOPEN) {
2171 throwSyntaxError("'(' expected after 'define' keyword.");
2174 if (token == TT_COMMA) {
2177 throwSyntaxError("',' expected after first 'define' constant.");
2180 if (token == TT_COMMA) {
2184 if (token == TT_ARGCLOSE) {
2187 throwSyntaxError("')' expected after 'define' statement.");
2189 if (token == TT_SEMICOLON) {
2193 throwSyntaxError("';' expected after 'define' statement.");
2198 } else if (token == TT_function) {
2200 functionDefinition();
2202 } else if (token == TT_class) {
2208 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2209 } else if (token == TT_LISTOPEN) {
2210 // compoundStatement
2212 if (token != TT_LISTCLOSE) {
2215 if (token == TT_LISTCLOSE) {
2219 throwSyntaxError("'}' expected.");
2222 if (token != TT_SEMICOLON) {
2225 if (token == TT_SEMICOLON) {
2230 throwSyntaxError("';' expected after expression.");
2237 private void classDeclarator() throws CoreException {
2239 //identifier 'extends' identifier
2240 if (token == TT_IDENTIFIER) {
2242 if (token == TT_extends) {
2244 if (token == TT_IDENTIFIER) {
2247 throwSyntaxError("Class name expected after keyword 'extends'.");
2251 throwSyntaxError("Class name expected after keyword 'class'.");
2255 private void classBody() throws CoreException {
2256 //'{' [class-element-list] '}'
2257 if (token == TT_LISTOPEN) {
2259 if (token != TT_LISTCLOSE) {
2262 if (token == TT_LISTCLOSE) {
2265 throwSyntaxError("'}' expected at end of class body.");
2268 throwSyntaxError("'{' expected at start of class body.");
2272 private void classElementList() throws CoreException {
2275 } while (token == TT_function || token == TT_var);
2278 private void classElement() throws CoreException {
2280 //function-definition
2281 if (token == TT_function) {
2283 functionDefinition();
2284 } else if (token == TT_var) {
2288 throwSyntaxError("'function' or 'var' expected.");
2292 private void classProperty() throws CoreException {
2293 //'var' variable ';'
2294 //'var' variable '=' constant ';'
2296 if (token == TT_VARIABLE) {
2298 if (token == TT_ASSIGN) {
2303 throwSyntaxError("Variable expected after keyword 'var'.");
2305 if (token != TT_COMMA) {
2310 if (token == TT_SEMICOLON) {
2313 throwSyntaxError("';' expected after variable declaration.");
2317 private void functionDefinition() throws CoreException {
2318 functionDeclarator();
2319 compoundStatement();
2322 private void functionDeclarator() throws CoreException {
2323 //identifier '(' [parameter-list] ')'
2324 if (token == TT_AMPERSAND) {
2327 if (token == TT_IDENTIFIER) {
2329 if (token == TT_ARGOPEN) {
2332 throwSyntaxError("'(' expected in function declaration.");
2334 if (token != TT_ARGCLOSE) {
2337 if (token != TT_ARGCLOSE) {
2338 throwSyntaxError("')' expected in function declaration.");
2345 private void parameterList() throws CoreException {
2346 //parameter-declaration
2347 //parameter-list ',' parameter-declaration
2349 parameterDeclaration();
2350 if (token != TT_COMMA) {
2357 private void parameterDeclaration() throws CoreException {
2359 //variable-reference
2360 if (token == TT_AMPERSAND) {
2362 if (token == TT_VARIABLE) {
2365 throwSyntaxError("Variable expected after reference operator '&'.");
2368 //variable '=' constant
2369 if (token == TT_VARIABLE) {
2371 if (token == TT_ASSIGN) {
2379 private void labeledStatementList() throws CoreException {
2380 if (token != TT_case && token != TT_default) {
2381 throwSyntaxError("'case' or 'default' expected.");
2384 if (token == TT_case) {
2387 if (token == TT_DDOT) {
2389 if (token == TT_case || token == TT_default) { // empty case statement ?
2393 } else if (token == TT_SEMICOLON) {
2394 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2396 if (token == TT_case) { // empty case statement ?
2401 throwSyntaxError("':' character after 'case' constant expected.");
2403 } else { // TT_default
2405 if (token == TT_DDOT) {
2409 throwSyntaxError("':' character after 'default' expected.");
2412 } while (token == TT_case || token == TT_default);
2415 // public void labeledStatement() {
2416 // if (token == TT_case) {
2419 // if (token == TT_DDOT) {
2423 // throwSyntaxError("':' character after 'case' constant expected.");
2426 // } else if (token == TT_default) {
2428 // if (token == TT_DDOT) {
2432 // throwSyntaxError("':' character after 'default' expected.");
2438 // public void expressionStatement() {
2441 // private void inclusionStatement() {
2444 // public void compoundStatement() {
2447 // public void selectionStatement() {
2450 // public void iterationStatement() {
2453 // public void jumpStatement() {
2456 // public void outputStatement() {
2459 // public void scopeStatement() {
2462 // public void flowStatement() {
2465 // public void definitionStatement() {
2468 private void ifStatement() throws CoreException {
2469 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2470 if (token == TT_DDOT) {
2476 if (token == TT_DDOT) {
2480 if (token == TT_if) { //'else if'
2482 elseifStatementList();
2484 throwSyntaxError("':' expected after 'else'.");
2490 elseifStatementList();
2494 if (token != TT_endif) {
2495 throwSyntaxError("'endif' expected.");
2498 if (token != TT_SEMICOLON) {
2499 throwSyntaxError("';' expected after if-statement.");
2503 // statement [else-statement]
2505 if (token == TT_elseif) {
2507 if (token == TT_ARGOPEN) {
2510 throwSyntaxError("'(' expected after 'elseif' keyword.");
2513 if (token == TT_ARGCLOSE) {
2516 throwSyntaxError("')' expected after 'elseif' condition.");
2519 } else if (token == TT_else) {
2526 private void elseifStatementList() throws CoreException {
2532 if (token == TT_DDOT) {
2537 if (token == TT_if) { //'else if'
2540 throwSyntaxError("':' expected after 'else'.");
2553 private void elseifStatement() throws CoreException {
2554 if (token == TT_ARGOPEN) {
2557 if (token != TT_ARGOPEN) {
2558 throwSyntaxError("')' expected in else-if-statement.");
2561 if (token != TT_DDOT) {
2562 throwSyntaxError("':' expected in else-if-statement.");
2569 private void switchStatement() throws CoreException {
2570 if (token == TT_DDOT) {
2571 // ':' [labeled-statement-list] 'endswitch' ';'
2573 labeledStatementList();
2574 if (token != TT_endswitch) {
2575 throwSyntaxError("'endswitch' expected.");
2578 if (token != TT_SEMICOLON) {
2579 throwSyntaxError("';' expected after switch-statement.");
2583 // '{' [labeled-statement-list] '}'
2584 if (token != TT_LISTOPEN) {
2585 throwSyntaxError("'{' expected in switch statement.");
2588 if (token != TT_LISTCLOSE) {
2589 labeledStatementList();
2591 if (token != TT_LISTCLOSE) {
2592 throwSyntaxError("'}' expected in switch statement.");
2599 private void forStatement() throws CoreException {
2600 if (token == TT_DDOT) {
2603 if (token != TT_endfor) {
2604 throwSyntaxError("'endfor' expected.");
2607 if (token != TT_SEMICOLON) {
2608 throwSyntaxError("';' expected after for-statement.");
2616 private void whileStatement() throws CoreException {
2617 // ':' statement-list 'endwhile' ';'
2618 if (token == TT_DDOT) {
2621 if (token != TT_endwhile) {
2622 throwSyntaxError("'endwhile' expected.");
2625 if (token != TT_SEMICOLON) {
2626 throwSyntaxError("';' expected after while-statement.");
2634 private void foreachStatement() throws CoreException {
2635 if (token == TT_DDOT) {
2638 if (token != TT_endforeach) {
2639 throwSyntaxError("'endforeach' expected.");
2642 if (token != TT_SEMICOLON) {
2643 throwSyntaxError("';' expected after foreach-statement.");
2651 private void exitStatus() throws CoreException {
2652 if (token == TT_ARGOPEN) {
2655 throwSyntaxError("'(' expected in 'exit-status'.");
2657 if (token != TT_ARGCLOSE) {
2660 if (token == TT_ARGCLOSE) {
2663 throwSyntaxError("')' expected after 'exit-status'.");
2667 private void expressionList() throws CoreException {
2670 if (token == TT_COMMA) {
2678 private void expression() throws CoreException {
2679 //todo: find a better way to get the expression
2680 expression = new StringBuffer();
2681 for (int i = chIndx;i<str.length();i++) {
2682 if (str.charAt(i) == ';') {
2685 expression.append(str.charAt(i));
2687 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2690 logicalinclusiveorExpression();
2691 // while (token != TT_SEMICOLON) {
2697 private void postfixExpression() throws CoreException {
2699 boolean castFlag = false;
2714 case TT_STRING_CONSTANT :
2717 case TT_INTERPOLATED_STRING :
2722 if (token == TT_IDENTIFIER) {
2723 // check if identifier is a type:
2725 String str = identifier.toLowerCase();
2726 for (int i = 0; i < PHP_TYPES.length; i++) {
2727 if (PHP_TYPES[i].equals(str)) {
2734 if (token != TT_ARGCLOSE) {
2735 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2745 if (token != TT_ARGCLOSE) {
2746 throwSyntaxError(") expected in postfix-expression.");
2750 case TT_DOUBLE_NUMBER :
2753 case TT_INT_NUMBER :
2756 case TT_DOLLAROPEN :
2759 if (token != TT_LISTCLOSE) {
2760 throwSyntaxError("'}' expected after indirect variable token '${'.");
2767 if (token == TT_LISTOPEN) {
2770 if (token != TT_LISTCLOSE) {
2771 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2774 } else if (token == TT_ARGOPEN) {
2776 if (token != TT_ARGCLOSE) {
2778 if (token != TT_ARGCLOSE) {
2779 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2785 case TT_IDENTIFIER :
2788 if (token == TT_ARGOPEN) {
2790 if (token != TT_ARGCLOSE) {
2792 if (token != TT_ARGCLOSE) {
2793 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2802 // if (token == TT_SEMICOLON) {
2806 // throwSyntaxError("';' expected after 'print' statement.");
2813 if (token == TT_ARGOPEN) {
2815 if (token == TT_COMMA) {
2819 if (token != TT_ARGCLOSE) {
2820 throwSyntaxError("')' expected after 'list' keyword.");
2823 // if (token == TT_SET) {
2825 // logicalinclusiveorExpression();
2828 throwSyntaxError("'(' expected after 'list' keyword.");
2833 // if (token != TT_SEMICOLON) {
2836 // if (token == TT_SEMICOLON) {
2840 // throwSyntaxError("';' expected after 'exit' expression.");
2847 // if (token != TT_SEMICOLON) {
2850 // if (token == TT_SEMICOLON) {
2854 // throwSyntaxError("';' expected after 'die' expression.");
2861 // if (token == TT_ARGOPEN) {
2863 // if (token == TT_COMMA) {
2866 // expressionList();
2867 // if (token != TT_ARGCLOSE) {
2868 // throwSyntaxError("')' expected after 'list' keyword.");
2871 // if (token == TT_SET) {
2873 // logicalinclusiveorExpression();
2876 // throwSyntaxError("'(' expected after 'list' keyword.");
2880 boolean while_flag = true;
2886 if (token != TT_PARTCLOSE) {
2887 throwSyntaxError("] expected in postfix-expression.");
2891 case TT_DDOT2 : // ::
2894 if (token > TT_KEYWORD) {
2896 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2902 // if (token == TT_ARGOPEN) {
2904 // expressionList();
2905 // if (token != TT_ARGCLOSE) {
2906 // throwSyntaxError(") expected after variable '" + ident + "'.");
2911 case TT_IDENTIFIER :
2918 if (token != TT_LISTCLOSE) {
2919 throwSyntaxError("} expected in postfix-expression.");
2924 throwSyntaxError("Syntax error after '->' token.");
2925 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2926 if (token == TT_PARTOPEN) {
2929 if (token != TT_PARTCLOSE) {
2930 throwSyntaxError("] expected after '->'.");
2934 if (token == TT_ARGOPEN) {
2937 if (token != TT_ARGCLOSE) {
2938 throwSyntaxError(") expected after '->'.");
2942 if (token == TT_LISTOPEN) {
2945 if (token != TT_LISTCLOSE) {
2946 throwSyntaxError("} expected after '->'.");
2966 private void unaryExpression() throws CoreException {
2976 // '@' '&' '*' '+' '-' '~' '!'
3006 postfixExpression();
3010 private void castExpression() throws CoreException {
3011 // if (token == TT_ARGOPEN) {
3014 // if (token != TT_ARGCLOSE) {
3015 // throwSyntaxError(") expected after cast-expression.");
3022 private void typeName() throws CoreException {
3023 //'string' 'unset' 'array' 'object'
3025 //'real' 'double' 'float'
3028 if (token == TT_IDENTIFIER) {
3030 String str = identifier.toLowerCase();
3032 for (int i = 0; i < PHP_TYPES.length; i++) {
3033 if (PHP_TYPES[i].equals(str)) {
3038 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3041 private void assignExpression() throws CoreException {
3043 if (token == TT_ASSIGN) { // =
3045 logicalinclusiveorExpression();
3046 } else if (token == TT_DOTASSIGN) { // .=
3048 logicalinclusiveorExpression();
3049 } else if (token == TT_FOREACH) { // =>
3051 logicalinclusiveorExpression();
3052 } else if (token == TT_ADDTO) { // +=
3054 logicalinclusiveorExpression();
3055 } else if (token == TT_SUBTRACTFROM) { // -=
3057 logicalinclusiveorExpression();
3058 } else if (token == TT_TIMESBY) { // *=
3060 logicalinclusiveorExpression();
3061 } else if (token == TT_DIVIDEBY) { // *=
3063 logicalinclusiveorExpression();
3064 } else if (token == TT_MODASSIGN) { // %=
3066 logicalinclusiveorExpression();
3067 } else if (token == TT_ANDASSIGN) { // &=
3069 logicalinclusiveorExpression();
3070 } else if (token == TT_POWASSIGN) { // ^=
3072 logicalinclusiveorExpression();
3073 } else if (token == TT_LSHIFTASSIGN) { // <<=
3075 logicalinclusiveorExpression();
3076 } else if (token == TT_RSHIFTASSIGN) { // >>=
3078 logicalinclusiveorExpression();
3079 } else if (token == TT_TILDEASSIGN) { // ~=
3081 logicalinclusiveorExpression();
3085 private void multiplicativeExpression() throws CoreException {
3088 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3095 private void concatenationExpression() throws CoreException {
3097 multiplicativeExpression();
3098 if (token != TT_DOT) {
3105 private void additiveExpression() throws CoreException {
3107 concatenationExpression();
3108 if (token != TT_ADD && token != TT_SUBTRACT) {
3115 private void shiftExpression() throws CoreException {
3117 additiveExpression();
3118 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3125 private void relationalExpression() throws CoreException {
3128 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3135 private void identicalExpression() throws CoreException {
3137 relationalExpression();
3138 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3145 private void equalityExpression() throws CoreException {
3147 identicalExpression();
3148 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3155 private void ternaryExpression() throws CoreException {
3156 equalityExpression();
3157 if (token == TT_QUESTIONMARK) {
3160 if (token == TT_DDOT) {
3164 throwSyntaxError("':' expected in ternary operator '? :'.");
3169 private void andExpression() throws CoreException {
3171 ternaryExpression();
3172 if (token != TT_AMPERSAND) {
3179 private void exclusiveorExpression() throws CoreException {
3182 if (token != TT_POW) {
3189 private void inclusiveorExpression() throws CoreException {
3191 exclusiveorExpression();
3192 if (token != TT_LINE) {
3199 private void booleanandExpression() throws CoreException {
3201 inclusiveorExpression();
3202 if (token != TT_AND) {
3209 private void booleanorExpression() throws CoreException {
3211 booleanandExpression();
3212 if (token != TT_OR) {
3219 private void logicalandExpression() throws CoreException {
3221 booleanorExpression();
3222 if (token != TT_and) {
3229 private void logicalexclusiveorExpression() throws CoreException {
3231 logicalandExpression();
3232 if (token != TT_xor) {
3239 private void logicalinclusiveorExpression() throws CoreException {
3241 logicalexclusiveorExpression();
3242 if (token != TT_or) {
3249 // public void assignmentExpression() {
3250 // if (token == TT_VARIABLE) {
3252 // if (token == TT_SET) {
3254 // logicalinclusiveorExpression();
3257 // logicalinclusiveorExpression();
3261 private void variableList() throws CoreException {
3264 if (token == TT_COMMA) {
3272 private void variable() throws CoreException {
3273 if (token == TT_DOLLAROPEN) {
3277 if (token != TT_LISTCLOSE) {
3278 throwSyntaxError("'}' expected after indirect variable token '${'.");
3282 if (token == TT_VARIABLE) {
3284 if (token == TT_PARTOPEN) {
3287 if (token != TT_PARTCLOSE) {
3288 throwSyntaxError("']' expected in variable-list.");
3291 } else if (token == TT_ASSIGN) {
3296 throwSyntaxError("$-variable expected in variable-list.");
3301 private void constant() throws CoreException {
3307 case TT_DOUBLE_NUMBER :
3310 case TT_INT_NUMBER :
3314 throwSyntaxError("Constant expected after '+' presign.");
3320 case TT_DOUBLE_NUMBER :
3323 case TT_INT_NUMBER :
3327 throwSyntaxError("Constant expected after '-' presign.");
3339 case TT_IDENTIFIER :
3342 if (token == TT_ARGOPEN) {
3344 if (token != TT_ARGCLOSE) {
3346 if (token != TT_ARGCLOSE) {
3347 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3353 case TT_STRING_CONSTANT :
3356 case TT_INTERPOLATED_STRING :
3359 case TT_DOUBLE_NUMBER :
3362 case TT_INT_NUMBER :
3366 throwSyntaxError("Constant expected.");
3371 * Call the php parse command ( php -l -f <filename> )
3372 * and create markers according to the external parser output
3374 public static void phpExternalParse(IFile file) {
3375 //IFile file = (IFile) resource;
3376 IPath path = file.getFullPath();
3377 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3378 String filename = file.getLocation().toString();
3380 String[] arguments = { filename };
3381 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3382 String command = form.format(arguments);
3384 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3387 // parse the buffer to find the errors and warnings
3388 createMarkers(parserResult, file);
3389 } catch (CoreException e) {
3394 * Create markers according to the external parser output
3396 private static void createMarkers(String output, IFile file) throws CoreException {
3397 // delete all markers
3398 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3402 boolean flag = true;
3403 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3404 // newer php error output (tested with 4.2.3)
3405 scanLine(output, file, indx, brIndx);
3410 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3411 // older php error output (tested with 4.2.3)
3412 scanLine(output, file, indx, brIndx);
3418 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3420 String outLineNumberString;
3421 StringBuffer lineNumberBuffer = new StringBuffer(10);
3423 current = output.substring(indx, brIndx);
3425 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3426 int onLine = current.indexOf("on line <b>");
3428 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3429 for (int i = onLine; i < current.length(); i++) {
3430 ch = current.charAt(i);
3431 if ('0' <= ch && '9' >= ch) {
3432 lineNumberBuffer.append(ch);
3436 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3438 Hashtable attributes = new Hashtable();
3440 current = current.replaceAll("\n", "");
3441 current = current.replaceAll("<b>", "");
3442 current = current.replaceAll("</b>", "");
3443 MarkerUtilities.setMessage(attributes, current);
3445 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3446 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3447 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3448 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3450 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3451 MarkerUtilities.setLineNumber(attributes, lineNumber);
3452 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);