1 /**********************************************************************
2 Copyright (c) 2002 Klaus Hartlage - www.eclipseproject.de
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
9 Klaus Hartlage - www.eclipseproject.de
10 **********************************************************************/
11 package net.sourceforge.phpeclipse.phpeditor.phpparser;
13 import java.text.MessageFormat;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.Hashtable;
17 import java.util.Stack;
19 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
20 import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
21 import net.sourceforge.phpeclipse.phpeditor.PHPString;
22 import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
23 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
24 import org.eclipse.core.resources.IFile;
25 import org.eclipse.core.resources.IMarker;
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IPath;
28 import org.eclipse.jface.preference.IPreferenceStore;
29 import org.eclipse.jface.action.IAction;
30 import org.eclipse.ui.texteditor.MarkerUtilities;
32 public class PHPParser extends PHPKeywords {
33 // strings for external parser call
34 private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
35 private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
37 public static final int ERROR = 2;
38 public static final int WARNING = 1;
39 public static final int INFO = 0;
40 private IFile fileToParse;
41 private ArrayList phpList;
43 private int currentPHPString;
44 private boolean phpEnd;
46 private static HashMap keywordMap = null;
54 // row counter for syntax errors:
56 // column counter for syntax errors:
66 private boolean phpMode;
68 final static int TT_EOF = 0;
69 final static int TT_UNDEFINED = 1;
70 final static int TT_HTML = 2;
72 final static int TT_MOD = 30;
73 final static int TT_NOT = 31;
74 final static int TT_DOT = 32;
75 final static int TT_POW = 33;
76 final static int TT_DIV = 34;
77 final static int TT_MULTIPLY = 35;
78 final static int TT_SUBTRACT = 36;
79 final static int TT_ADD = 37;
80 final static int TT_EQUAL = 38;
81 final static int TT_UNEQUAL = 39;
82 final static int TT_GREATER = 40;
83 final static int TT_GREATEREQUAL = 41;
84 final static int TT_LESS = 42;
85 final static int TT_LESSEQUAL = 43;
86 final static int TT_AND = 44;
87 final static int TT_OR = 45;
88 final static int TT_HASH = 46;
89 final static int TT_DDOT = 47;
90 final static int TT_DOTASSIGN = 48;
92 final static int TT_ASSIGN = 49;
93 final static int TT_REF = 50;
94 final static int TT_FOREACH = 51;
95 final static int TT_AMPERSAND = 52;
96 final static int TT_DOLLARLISTOPEN = 53;
97 final static int TT_TILDE = 54;
98 final static int TT_TILDEASSIGN = 55;
99 final static int TT_MODASSIGN = 56;
100 final static int TT_POWASSIGN = 57;
101 final static int TT_RSHIFTASSIGN = 58;
102 final static int TT_LSHIFTASSIGN = 59;
103 final static int TT_ANDASSIGN = 60;
104 final static int TT_QUESTIONMARK = 61;
105 final static int TT_DDOT2 = 62;
106 final static int TT_AT = 63;
107 // final static int TT_HEREDOC = 64;
109 final static int TT_DOLLAROPEN = 127;
110 final static int TT_ARGOPEN = 128;
111 final static int TT_ARGCLOSE = 129;
112 final static int TT_LISTOPEN = 130;
113 final static int TT_LISTCLOSE = 131;
114 final static int TT_PARTOPEN = 132;
115 final static int TT_PARTCLOSE = 133;
116 final static int TT_COMMA = 134;
118 final static int TT_STRING = 136;
119 final static int TT_IDENTIFIER = 138;
120 final static int TT_DIGIT = 139;
121 final static int TT_SEMICOLON = 140;
122 final static int TT_SLOT = 141;
123 final static int TT_SLOTSEQUENCE = 142;
124 final static int TT_DECREMENT = 144;
125 final static int TT_INCREMENT = 145;
126 final static int TT_ADDTO = 146;
127 final static int TT_DIVIDEBY = 147;
128 final static int TT_SUBTRACTFROM = 148;
129 final static int TT_TIMESBY = 149;
130 final static int TT_VARIABLE = 150;
131 final static int TT_INT_NUMBER = 151;
132 final static int TT_DOUBLE_NUMBER = 152;
133 final static int TT_INTERPOLATED_STRING = 153;
134 final static int TT_STRING_CONSTANT = 154;
136 final static int TT_LSHIFT = 155;
137 final static int TT_RSHIFT = 156;
138 final static int TT_EX_EQUAL = 157;
139 final static int TT_EX_UNEQUAL = 158;
140 final static int TT_LINE = 159;
141 // final static int TT_AT = 153; // @
146 *@param sess Description of Parameter
149 public PHPParser(IFile fileToParse) {
150 if (keywordMap == null) {
151 keywordMap = new HashMap();
152 for (int i = 0; i < PHP_KEYWORS.length; i++) {
153 keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
156 this.currentPHPString = 0;
157 this.fileToParse = fileToParse;
163 this.columnCount = 0;
170 * Create marker for the parse error
172 private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
173 setMarker(fileToParse, message, lineNumber, errorLevel);
176 public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
178 Hashtable attributes = new Hashtable();
179 MarkerUtilities.setMessage(attributes, message);
180 switch (errorLevel) {
182 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
185 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
188 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
191 MarkerUtilities.setLineNumber(attributes, lineNumber);
192 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
196 private void throwSyntaxError(String error) {
198 if (str.length() < chIndx) {
201 // read until end-of-line
203 while (str.length() > eol) {
204 ch = str.charAt(eol++);
210 throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
213 private void throwSyntaxError(String error, int startRow) {
215 throw new SyntaxError(startRow, 0, " ", error);
219 * Method Declaration.
223 private void getChar() {
224 if (str.length() > chIndx) {
225 ch = str.charAt(chIndx++);
230 chIndx = str.length() + 1;
236 private void getNextToken_OldVersion() throws CoreException {
239 while (str.length() > chIndx) {
240 ch = str.charAt(chIndx++);
241 token = TT_UNDEFINED;
244 columnCount = chIndx;
245 continue; // while loop
247 if (str.length() == chIndx) {
250 if (!Character.isWhitespace(ch)) {
252 if (str.length() > chIndx) {
253 if (str.charAt(chIndx) == '{') {
255 token = TT_DOLLAROPEN;
262 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
266 if (ch >= '0' && ch <= '9') {
271 if (str.length() > chIndx) {
272 if (str.charAt(chIndx) == '/') {
274 // read comment until end of line:
275 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
279 } else if (str.charAt(chIndx) == '*') {
281 // multi line comment:
282 while (str.length() > chIndx) {
283 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
287 ch = str.charAt(chIndx++);
290 columnCount = chIndx;
296 } else if (ch == '#') {
297 // read comment until end of line:
298 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
302 } else if (ch == '"') {
303 // read string until end
304 boolean openString = true;
305 while (str.length() > chIndx) {
306 ch = str.charAt(chIndx++);
308 if (str.length() > chIndx) {
309 ch = str.charAt(chIndx++);
311 } else if (ch == '"') {
314 } else if (ch == '\n') {
316 columnCount = chIndx;
320 throwSyntaxError("Open string character '\"' at end of file.");
322 token = TT_INTERPOLATED_STRING;
324 } else if (ch == '\'') {
325 // read string until end
326 boolean openString = true;
327 int startRow = rowCount;
328 while (str.length() > chIndx) {
329 ch = str.charAt(chIndx++);
331 if (str.length() > chIndx) {
332 ch = str.charAt(chIndx++);
334 } else if (ch == '\'') {
337 } else if (ch == '\n') {
339 columnCount = chIndx;
343 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
345 token = TT_STRING_CONSTANT;
347 } else if (ch == '`') {
348 // read string until end
349 boolean openString = true;
350 int startRow = rowCount;
351 while (str.length() > chIndx) {
352 ch = str.charAt(chIndx++);
354 if (str.length() > chIndx) {
355 ch = str.charAt(chIndx++);
357 } else if (ch == '`') {
360 } else if (ch == '\n') {
362 columnCount = chIndx;
366 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
368 token = TT_STRING_CONSTANT;
387 token = TT_LISTCLOSE;
395 token = TT_PARTCLOSE;
403 token = TT_QUESTIONMARK;
410 if (str.length() > chIndx) {
411 if (str.charAt(chIndx) == '=') {
413 token = TT_TILDEASSIGN;
421 if (str.length() > chIndx) {
422 if (str.charAt(chIndx) == '=') {
424 token = TT_DOTASSIGN;
437 if (str.length() > chIndx) {
438 if (str.charAt(chIndx) == '=') {
440 token = TT_MODASSIGN;
447 token = TT_SEMICOLON;
452 if (str.length() > chIndx) {
453 if (str.charAt(chIndx) == '=') {
455 token = TT_POWASSIGN;
464 if (str.length() > chIndx) {
465 if (str.charAt(chIndx) == '=') {
476 if (str.length() > chIndx) {
477 if (str.charAt(chIndx) == '*') {
483 if (str.charAt(chIndx) == '=') {
494 if (str.length() > chIndx) {
495 if (str.charAt(chIndx) == '+') {
497 token = TT_INCREMENT;
501 if (str.charAt(chIndx) == '=') {
511 if (str.length() > chIndx) {
512 if (str.charAt(chIndx) == '-') {
514 token = TT_DECREMENT;
518 if (str.charAt(chIndx) == '=') {
520 token = TT_SUBTRACTFROM;
524 if (str.charAt(chIndx) == '>') {
536 if (str.length() > chIndx) {
537 ch = str.charAt(chIndx);
542 if (str.length() > chIndx) {
543 ch = str.charAt(chIndx);
564 if (str.length() > chIndx) {
565 if (str.charAt(chIndx) == '=') {
568 if (str.length() > chIndx) {
569 ch = str.charAt(chIndx);
573 token = TT_EX_UNEQUAL;
584 if (str.length() > chIndx) {
585 if (str.charAt(chIndx) == '=') {
587 token = TT_GREATEREQUAL;
590 if (str.charAt(chIndx) == '>') {
593 if (str.length() > chIndx) {
594 if (str.charAt(chIndx) == '=') {
596 token = TT_RSHIFTASSIGN;
608 if (str.length() > chIndx) {
609 if (str.charAt(chIndx) == '=') {
611 token = TT_LESSEQUAL;
615 if (str.charAt(chIndx) == '<') {
618 if (str.charAt(chIndx) == '<') {
620 int startRow = rowCount;
621 if (str.length() > chIndx) {
623 ch = str.charAt(++chIndx);
624 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
627 token = TT_STRING_CONSTANT;
628 while (str.length() > chIndx) {
629 ch = str.charAt(chIndx++);
631 if (str.length() >= chIndx + identifier.length()) {
632 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
633 chIndx += identifier.length();
641 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
642 } else if (str.charAt(chIndx) == '=') {
644 token = TT_LSHIFTASSIGN;
656 if (str.length() > chIndx) {
657 if (str.charAt(chIndx) == '|') {
667 token = TT_AMPERSAND;
668 if (str.length() > chIndx) {
669 if (str.charAt(chIndx) == '&') {
674 if (str.charAt(chIndx) == '=') {
676 token = TT_ANDASSIGN;
685 if (str.length() > chIndx) {
686 if (str.charAt(chIndx) == ':') {
701 throwSyntaxError("unexpected character: '" + ch + "'");
704 if (token == TT_UNDEFINED) {
705 throwSyntaxError("token not found");
712 chIndx = str.length() + 1;
717 if (phpList != null) {
718 if (currentPHPString < phpList.size()) {
719 token = TT_UNDEFINED;
720 temp = (PHPString) phpList.get(currentPHPString++);
721 this.str = temp.getPHPString();
724 this.rowCount = temp.getLineNumber();
725 this.columnCount = 0;
729 token = TT_UNDEFINED;
735 * gets the next token from input
737 private void getNextToken() throws CoreException {
738 boolean phpFound = false;
745 while (str.length() > chIndx) {
746 token = TT_UNDEFINED;
747 ch = str.charAt(chIndx++);
753 ch2 = str.charAt(chIndx++);
755 ch2 = str.charAt(chIndx++);
756 if (Character.isWhitespace(ch2)) {
761 } else if (ch2 == 'p') {
762 ch2 = str.charAt(chIndx++);
764 ch2 = str.charAt(chIndx++);
773 } else if (ch2 == 'P') {
774 ch2 = str.charAt(chIndx++);
776 ch2 = str.charAt(chIndx++);
795 while (str.length() > chIndx) {
796 ch = str.charAt(chIndx++);
797 token = TT_UNDEFINED;
800 columnCount = chIndx;
801 continue; // while loop
803 if (str.length() == chIndx) {
806 if (!Character.isWhitespace(ch)) {
808 if (str.length() > chIndx) {
809 if (str.charAt(chIndx) == '{') {
811 token = TT_DOLLAROPEN;
818 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
822 if (ch >= '0' && ch <= '9') {
827 if (str.length() > chIndx) {
828 if (str.charAt(chIndx) == '/') {
831 // read comment until end of line:
832 while ((str.length() > chIndx) && (ch != '\n')) {
833 ch = str.charAt(chIndx++);
835 ch2 = str.charAt(chIndx);
849 } else if (str.charAt(chIndx) == '*') {
851 // multi line comment:
852 while (str.length() > chIndx) {
853 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
857 ch = str.charAt(chIndx++);
860 columnCount = chIndx;
866 } else if (ch == '#') {
867 // read comment until end of line:
868 while ((str.length() > chIndx) && (ch != '\n')) {
869 ch = str.charAt(chIndx++);
871 ch2 = str.charAt(chIndx);
885 } else if (ch == '"') {
886 // read string until end
887 boolean openString = true;
888 while (str.length() > chIndx) {
889 ch = str.charAt(chIndx++);
891 if (str.length() > chIndx) {
892 ch = str.charAt(chIndx++);
894 } else if (ch == '"') {
897 } else if (ch == '\n') {
899 columnCount = chIndx;
903 throwSyntaxError("Open string character '\"' at end of file.");
905 token = TT_INTERPOLATED_STRING;
907 } else if (ch == '\'') {
908 // read string until end
909 boolean openString = true;
910 int startRow = rowCount;
911 while (str.length() > chIndx) {
912 ch = str.charAt(chIndx++);
914 if (str.length() > chIndx) {
915 ch = str.charAt(chIndx++);
917 } else if (ch == '\'') {
920 } else if (ch == '\n') {
922 columnCount = chIndx;
926 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
928 token = TT_STRING_CONSTANT;
930 } else if (ch == '`') {
931 // read string until end
932 boolean openString = true;
933 int startRow = rowCount;
934 while (str.length() > chIndx) {
935 ch = str.charAt(chIndx++);
937 if (str.length() > chIndx) {
938 ch = str.charAt(chIndx++);
940 } else if (ch == '`') {
943 } else if (ch == '\n') {
945 columnCount = chIndx;
949 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
951 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
952 token = TT_STRING_CONSTANT;
971 token = TT_LISTCLOSE;
979 token = TT_PARTCLOSE;
987 token = TT_QUESTIONMARK;
988 if (str.length() > chIndx) {
989 if (str.charAt(chIndx) == '>') {
1005 if (str.length() > chIndx) {
1006 if (str.charAt(chIndx) == '=') {
1008 token = TT_TILDEASSIGN;
1016 if (str.length() > chIndx) {
1017 if (str.charAt(chIndx) == '=') {
1019 token = TT_DOTASSIGN;
1032 if (str.length() > chIndx) {
1033 if (str.charAt(chIndx) == '=') {
1035 token = TT_MODASSIGN;
1042 token = TT_SEMICOLON;
1047 if (str.length() > chIndx) {
1048 if (str.charAt(chIndx) == '=') {
1050 token = TT_POWASSIGN;
1059 if (str.length() > chIndx) {
1060 if (str.charAt(chIndx) == '=') {
1062 token = TT_DIVIDEBY;
1070 token = TT_MULTIPLY;
1071 if (str.length() > chIndx) {
1072 if (str.charAt(chIndx) == '*') {
1078 if (str.charAt(chIndx) == '=') {
1089 if (str.length() > chIndx) {
1090 if (str.charAt(chIndx) == '+') {
1092 token = TT_INCREMENT;
1096 if (str.charAt(chIndx) == '=') {
1105 token = TT_SUBTRACT;
1106 if (str.length() > chIndx) {
1107 if (str.charAt(chIndx) == '-') {
1109 token = TT_DECREMENT;
1113 if (str.charAt(chIndx) == '=') {
1115 token = TT_SUBTRACTFROM;
1119 if (str.charAt(chIndx) == '>') {
1131 if (str.length() > chIndx) {
1132 ch = str.charAt(chIndx);
1137 if (str.length() > chIndx) {
1138 ch = str.charAt(chIndx);
1142 token = TT_EX_EQUAL;
1159 if (str.length() > chIndx) {
1160 if (str.charAt(chIndx) == '=') {
1163 if (str.length() > chIndx) {
1164 ch = str.charAt(chIndx);
1168 token = TT_EX_UNEQUAL;
1179 if (str.length() > chIndx) {
1180 if (str.charAt(chIndx) == '=') {
1182 token = TT_GREATEREQUAL;
1185 if (str.charAt(chIndx) == '>') {
1188 if (str.length() > chIndx) {
1189 if (str.charAt(chIndx) == '=') {
1191 token = TT_RSHIFTASSIGN;
1203 if (str.length() > chIndx) {
1204 if (str.charAt(chIndx) == '=') {
1206 token = TT_LESSEQUAL;
1210 if (str.charAt(chIndx) == '<') {
1213 if (str.charAt(chIndx) == '<') {
1215 int startRow = rowCount;
1216 if (str.length() > chIndx) {
1218 ch = str.charAt(++chIndx);
1219 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1222 token = TT_STRING_CONSTANT;
1223 while (str.length() > chIndx) {
1224 ch = str.charAt(chIndx++);
1226 if (str.length() >= chIndx + identifier.length()) {
1227 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1228 chIndx += identifier.length();
1236 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1237 } else if (str.charAt(chIndx) == '=') {
1239 token = TT_LSHIFTASSIGN;
1251 if (str.length() > chIndx) {
1252 if (str.charAt(chIndx) == '|') {
1262 token = TT_AMPERSAND;
1263 if (str.length() > chIndx) {
1264 if (str.charAt(chIndx) == '&') {
1269 if (str.charAt(chIndx) == '=') {
1271 token = TT_ANDASSIGN;
1280 if (str.length() > chIndx) {
1281 if (str.charAt(chIndx) == ':') {
1296 throwSyntaxError("unexpected character: '" + ch + "'");
1299 if (token == TT_UNDEFINED) {
1300 throwSyntaxError("token not found");
1307 } catch (StringIndexOutOfBoundsException e) {
1308 // catched from charAt
1311 chIndx = str.length() + 1;
1316 // if (phpList != null) {
1317 // if (currentPHPString < phpList.size()) {
1318 // token = TT_UNDEFINED;
1319 // temp = (PHPString) phpList.get(currentPHPString++);
1320 // this.str = temp.getPHPString();
1321 // this.token = TT_EOF;
1323 // this.rowCount = temp.getLineNumber();
1324 // this.columnCount = 0;
1328 // token = TT_UNDEFINED;
1334 private void getIdentifier() {
1335 StringBuffer ident = new StringBuffer();
1340 // attention recursive call:
1342 token = TT_VARIABLE;
1345 token = TT_IDENTIFIER;
1349 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1353 identifier = ident.toString();
1356 // determine if this identitfer is a keyword
1357 // @todo improve this in future version
1358 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1360 token = i.intValue();
1364 private void getNumber() {
1365 StringBuffer inum = new StringBuffer();
1374 // determine number conversions:
1375 if (firstCh == '0') {
1404 if (numFormat == 16) {
1405 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1410 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1411 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1412 if (ch == '.' && dFlag != ' ') {
1415 if ((dFlag == 'E') || (dFlag == 'e')) {
1421 if ((ch == '-') || (ch == '+')) {
1435 doubleNumber = new Double(inum.toString());
1436 token = TT_DOUBLE_NUMBER;
1439 longNumber = Long.valueOf(inum.toString(), numFormat);
1440 token = TT_INT_NUMBER;
1444 } catch (Throwable e) {
1445 throwSyntaxError("Number format error: " + inum.toString());
1449 public void htmlParserTester(String input) {
1451 int startLineNumber = 1;
1455 boolean phpMode = false;
1456 boolean phpFound = false;
1458 phpList = new ArrayList();
1459 currentPHPString = 0;
1463 while (i < input.length()) {
1464 ch = input.charAt(i++);
1468 if ((!phpMode) && ch == '<') {
1469 ch2 = input.charAt(i++);
1471 ch2 = input.charAt(i++);
1472 if (Character.isWhitespace(ch2)) {
1477 startLineNumber = lineNumber;
1479 } else if (ch2 == 'p') {
1480 ch2 = input.charAt(i++);
1482 ch2 = input.charAt(i++);
1487 startLineNumber = lineNumber;
1493 } else if (ch2 == 'P') {
1494 ch2 = input.charAt(i++);
1496 ch2 = input.charAt(i++);
1501 startLineNumber = lineNumber;
1514 if (ch == '/' && i < input.length()) {
1515 ch2 = input.charAt(i++);
1517 while (i < input.length()) {
1518 ch = input.charAt(i++);
1519 if (ch == '?' && i < input.length()) {
1520 ch2 = input.charAt(i++);
1524 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1528 } else if (ch == '\n') {
1534 } else if (ch2 == '*') {
1535 // multi-line comment
1536 while (i < input.length()) {
1537 ch = input.charAt(i++);
1540 } else if (ch == '*' && i < input.length()) {
1541 ch2 = input.charAt(i++);
1552 } else if (ch == '#') {
1553 while (i < input.length()) {
1554 ch = input.charAt(i++);
1555 if (ch == '?' && i < input.length()) {
1556 ch2 = input.charAt(i++);
1560 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1564 } else if (ch == '\n') {
1570 } else if (ch == '"') {
1572 while (i < input.length()) {
1573 ch = input.charAt(i++);
1576 } else if (ch == '\\' && i < input.length()) { // escape
1578 } else if (ch == '"') {
1583 } else if (ch == '\'') {
1585 while (i < input.length()) {
1586 ch = input.charAt(i++);
1589 } else if (ch == '\\' && i < input.length()) { // escape
1591 } else if (ch == '\'') {
1598 if (ch == '?' && i < input.length()) {
1599 ch2 = input.charAt(i++);
1603 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1612 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1615 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1616 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1618 // for (int j=0;j<phpList.size();j++) {
1619 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1620 // int startIndx = temp.length()-10;
1621 // if (startIndx<0) {
1624 // System.out.println(temp.substring(startIndx)+"?>");
1626 phpParserTester(null, 1);
1628 // for(int j=0;j<phpList.size();j++) {
1629 // temp = (PHPString) phpList.get(j);
1630 // parser.start(temp.getPHPString(), temp.getLineNumber());
1633 } catch (CoreException e) {
1637 public void phpParserTester(String s, int rowCount) throws CoreException {
1640 if (phpList.size() != 0) {
1641 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1644 this.token = TT_EOF;
1646 this.rowCount = rowCount;
1647 this.columnCount = 0;
1648 this.phpEnd = false;
1649 this.phpMode = true;
1653 if (token != TT_EOF && token != TT_UNDEFINED) {
1656 if (token != TT_EOF && token != TT_UNDEFINED) {
1657 if (token == TT_ARGCLOSE) {
1658 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1660 if (token == TT_LISTCLOSE) {
1661 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1663 if (token == TT_PARTCLOSE) {
1664 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1667 if (token == TT_ARGOPEN) {
1668 throwSyntaxError("Read character '('; end-of-file not reached.");
1670 if (token == TT_LISTOPEN) {
1671 throwSyntaxError("Read character '{'; end-of-file not reached.");
1673 if (token == TT_PARTOPEN) {
1674 throwSyntaxError("Read character '['; end-of-file not reached.");
1677 throwSyntaxError("End-of-file not reached.");
1680 } catch (SyntaxError err) {
1684 setMarker(err.getMessage(), err.getLine(), ERROR);
1686 // if an error occured,
1687 // try to find keywords 'class' or 'function'
1688 // to parse the rest of the string
1689 while (token != TT_EOF && token != TT_UNDEFINED) {
1690 if (token == TT_class || token == TT_function) {
1695 if (token == TT_EOF || token == TT_UNDEFINED) {
1704 * Parses a string with php tags
1705 * i.e. '<body> <?php phpinfo() ?> </body>'
1707 public void parse(String s) throws CoreException {
1709 this.token = TT_EOF;
1712 this.columnCount = 0;
1713 this.phpEnd = false;
1714 this.phpMode = false;
1718 if (token != TT_EOF && token != TT_UNDEFINED) {
1721 if (token != TT_EOF && token != TT_UNDEFINED) {
1722 if (token == TT_ARGCLOSE) {
1723 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1725 if (token == TT_LISTCLOSE) {
1726 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1728 if (token == TT_PARTCLOSE) {
1729 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1732 if (token == TT_ARGOPEN) {
1733 throwSyntaxError("Read character '('; end-of-file not reached.");
1735 if (token == TT_LISTOPEN) {
1736 throwSyntaxError("Read character '{'; end-of-file not reached.");
1738 if (token == TT_PARTOPEN) {
1739 throwSyntaxError("Read character '['; end-of-file not reached.");
1742 throwSyntaxError("End-of-file not reached.");
1745 } catch (SyntaxError sytaxErr1) {
1746 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1748 // if an error occured,
1749 // try to find keywords 'class' or 'function'
1750 // to parse the rest of the string
1751 while (token != TT_EOF && token != TT_UNDEFINED) {
1752 if (token == TT_class || token == TT_function) {
1757 if (token == TT_EOF || token == TT_UNDEFINED) {
1760 } catch (SyntaxError sytaxErr2) {
1761 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1769 public PHPOutlineInfo parseInfo(Object parent, String s) {
1770 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1771 // Stack stack = new Stack();
1772 // stack.push(outlineInfo.getDeclarations());
1775 this.token = TT_EOF;
1778 this.columnCount = 0;
1779 this.phpEnd = false;
1780 this.phpMode = false;
1784 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1785 } catch (CoreException e) {
1790 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPClassDeclaration current, boolean goBack) {
1791 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1792 PHPClassDeclaration temp;
1794 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1796 while (token != TT_EOF && token != TT_UNDEFINED) {
1797 if (token == TT_VARIABLE) {
1798 outlineInfo.addVariable(identifier);
1800 } else if (token == TT_var) {
1802 if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1803 outlineInfo.addVariable(identifier);
1804 current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1807 } else if (token == TT_function) {
1809 if (token == TT_AMPERSAND) {
1812 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1813 outlineInfo.addVariable(identifier);
1814 current.add(new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length()));
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);
1825 while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1828 parseDeclarations(outlineInfo, temp, true);
1831 } else if (token == TT_LISTOPEN) {
1834 } else if (token == TT_LISTCLOSE) {
1837 if (counter == 0 && goBack) {
1844 } catch (CoreException e) {
1848 private void statementList() throws CoreException {
1851 if ((token == TT_LISTCLOSE)
1852 || (token == TT_case)
1853 || (token == TT_default)
1854 || (token == TT_elseif)
1855 || (token == TT_endif)
1856 || (token == TT_endfor)
1857 || (token == TT_endforeach)
1858 || (token == TT_endwhile)
1859 || (token == TT_endswitch)
1860 || (token == TT_EOF)
1861 || (token == TT_UNDEFINED)) {
1867 private void compoundStatement() throws CoreException {
1868 // '{' [statement-list] '}'
1869 if (token == TT_LISTOPEN) {
1872 throwSyntaxError("'{' expected in compound-statement.");
1874 if (token != TT_LISTCLOSE) {
1877 if (token == TT_LISTCLOSE) {
1880 throwSyntaxError("'}' expected in compound-statement.");
1884 private void statement() throws CoreException {
1885 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1886 String keyword = identifier;
1887 if (token == TT_include || token == TT_include_once) {
1890 if (token == TT_SEMICOLON) {
1894 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1899 } else if (token == TT_require || token == TT_require_once) {
1903 if (token == TT_SEMICOLON) {
1907 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1912 } else if (token == TT_if) {
1914 if (token == TT_ARGOPEN) {
1917 throwSyntaxError("'(' expected after 'if' keyword.");
1920 if (token == TT_ARGCLOSE) {
1923 throwSyntaxError("')' expected after 'if' condition.");
1928 } else if (token == TT_switch) {
1930 if (token == TT_ARGOPEN) {
1933 throwSyntaxError("'(' expected after 'switch' keyword.");
1936 if (token == TT_ARGCLOSE) {
1939 throwSyntaxError("')' expected after 'switch' condition.");
1943 } else if (token == TT_for) {
1945 if (token == TT_ARGOPEN) {
1948 throwSyntaxError("'(' expected after 'for' keyword.");
1950 if (token == TT_SEMICOLON) {
1954 if (token == TT_SEMICOLON) {
1957 throwSyntaxError("';' expected after 'for'.");
1960 if (token == TT_SEMICOLON) {
1964 if (token == TT_SEMICOLON) {
1967 throwSyntaxError("';' expected after 'for'.");
1970 if (token == TT_ARGCLOSE) {
1974 if (token == TT_ARGCLOSE) {
1977 throwSyntaxError("')' expected after 'for'.");
1982 } else if (token == TT_while) {
1984 if (token == TT_ARGOPEN) {
1987 throwSyntaxError("'(' expected after 'while' keyword.");
1990 if (token == TT_ARGCLOSE) {
1993 throwSyntaxError("')' expected after 'while' condition.");
1997 } else if (token == TT_do) {
1999 if (token == TT_LISTOPEN) {
2002 throwSyntaxError("'{' expected after 'do' keyword.");
2004 if (token != TT_LISTCLOSE) {
2007 if (token == TT_LISTCLOSE) {
2010 throwSyntaxError("'}' expected after 'do' keyword.");
2012 if (token == TT_while) {
2014 if (token == TT_ARGOPEN) {
2017 throwSyntaxError("'(' expected after 'while' keyword.");
2020 if (token == TT_ARGCLOSE) {
2023 throwSyntaxError("')' expected after 'while' condition.");
2026 throwSyntaxError("'while' expected after 'do' keyword.");
2028 if (token == TT_SEMICOLON) {
2032 throwSyntaxError("';' expected after do-while statement.");
2037 } else if (token == TT_foreach) {
2039 if (token == TT_ARGOPEN) {
2042 throwSyntaxError("'(' expected after 'foreach' keyword.");
2045 if (token == TT_as) {
2048 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2051 if (token == TT_FOREACH) {
2055 if (token == TT_ARGCLOSE) {
2058 throwSyntaxError("')' expected after 'foreach' expression.");
2063 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2065 if (token != TT_SEMICOLON) {
2068 if (token == TT_SEMICOLON) {
2072 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2078 } else if (token == TT_echo) {
2081 if (token == TT_SEMICOLON) {
2085 throwSyntaxError("';' expected after 'echo' statement.");
2090 // } else if (token == TT_print) {
2093 // if (token == TT_SEMICOLON) {
2097 // throwSyntaxError("';' expected after 'print' statement.");
2103 } else if (token == TT_global || token == TT_static) {
2106 if (token == TT_SEMICOLON) {
2110 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2116 // } else if (token == TT_unset) {
2118 // if (token == TT_ARGOPEN) {
2121 // throwSyntaxError("'(' expected after 'unset' keyword.");
2124 // if (token == TT_ARGCLOSE) {
2127 // throwSyntaxError("')' expected after 'unset' statement.");
2129 // if (token == TT_SEMICOLON) {
2133 // throwSyntaxError("';' expected after 'unset' statement.");
2139 // } else if (token == TT_exit || token == TT_die) {
2141 // if (token != TT_SEMICOLON) {
2144 // if (token == TT_SEMICOLON) {
2148 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2154 } else if (token == TT_define) {
2156 if (token == TT_ARGOPEN) {
2159 throwSyntaxError("'(' expected after 'define' keyword.");
2162 if (token == TT_COMMA) {
2165 throwSyntaxError("',' expected after first 'define' constant.");
2168 if (token == TT_COMMA) {
2172 if (token == TT_ARGCLOSE) {
2175 throwSyntaxError("')' expected after 'define' statement.");
2177 if (token == TT_SEMICOLON) {
2181 throwSyntaxError("';' expected after 'define' statement.");
2186 } else if (token == TT_function) {
2188 functionDefinition();
2190 } else if (token == TT_class) {
2196 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2197 } else if (token == TT_LISTOPEN) {
2198 // compoundStatement
2200 if (token != TT_LISTCLOSE) {
2203 if (token == TT_LISTCLOSE) {
2207 throwSyntaxError("'}' expected.");
2210 if (token != TT_SEMICOLON) {
2213 if (token == TT_SEMICOLON) {
2218 throwSyntaxError("';' expected after expression.");
2225 private void classDeclarator() throws CoreException {
2227 //identifier 'extends' identifier
2228 if (token == TT_IDENTIFIER) {
2230 if (token == TT_extends) {
2232 if (token == TT_IDENTIFIER) {
2235 throwSyntaxError("Class name expected after keyword 'extends'.");
2239 throwSyntaxError("Class name expected after keyword 'class'.");
2243 private void classBody() throws CoreException {
2244 //'{' [class-element-list] '}'
2245 if (token == TT_LISTOPEN) {
2247 if (token != TT_LISTCLOSE) {
2250 if (token == TT_LISTCLOSE) {
2253 throwSyntaxError("'}' expected at end of class body.");
2256 throwSyntaxError("'{' expected at start of class body.");
2260 private void classElementList() throws CoreException {
2263 } while (token == TT_function || token == TT_var);
2266 private void classElement() throws CoreException {
2268 //function-definition
2269 if (token == TT_function) {
2271 functionDefinition();
2272 } else if (token == TT_var) {
2276 throwSyntaxError("'function' or 'var' expected.");
2280 private void classProperty() throws CoreException {
2281 //'var' variable ';'
2282 //'var' variable '=' constant ';'
2284 if (token == TT_VARIABLE) {
2286 if (token == TT_ASSIGN) {
2291 throwSyntaxError("Variable expected after keyword 'var'.");
2293 if (token != TT_COMMA) {
2298 if (token == TT_SEMICOLON) {
2301 throwSyntaxError("';' expected after variable declaration.");
2305 private void functionDefinition() throws CoreException {
2306 functionDeclarator();
2307 compoundStatement();
2310 private void functionDeclarator() throws CoreException {
2311 //identifier '(' [parameter-list] ')'
2312 if (token == TT_AMPERSAND) {
2315 if (token == TT_IDENTIFIER) {
2317 if (token == TT_ARGOPEN) {
2320 throwSyntaxError("'(' expected in function declaration.");
2322 if (token != TT_ARGCLOSE) {
2325 if (token != TT_ARGCLOSE) {
2326 throwSyntaxError("')' expected in function declaration.");
2333 private void parameterList() throws CoreException {
2334 //parameter-declaration
2335 //parameter-list ',' parameter-declaration
2337 parameterDeclaration();
2338 if (token != TT_COMMA) {
2345 private void parameterDeclaration() throws CoreException {
2347 //variable-reference
2348 if (token == TT_AMPERSAND) {
2350 if (token == TT_VARIABLE) {
2353 throwSyntaxError("Variable expected after reference operator '&'.");
2356 //variable '=' constant
2357 if (token == TT_VARIABLE) {
2359 if (token == TT_ASSIGN) {
2367 private void labeledStatementList() throws CoreException {
2368 if (token != TT_case && token != TT_default) {
2369 throwSyntaxError("'case' or 'default' expected.");
2372 if (token == TT_case) {
2375 if (token == TT_DDOT) {
2377 if (token == TT_case || token == TT_default) { // empty case statement ?
2381 } else if (token == TT_SEMICOLON) {
2382 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2384 if (token == TT_case) { // empty case statement ?
2389 throwSyntaxError("':' character after 'case' constant expected.");
2391 } else { // TT_default
2393 if (token == TT_DDOT) {
2397 throwSyntaxError("':' character after 'default' expected.");
2400 } while (token == TT_case || token == TT_default);
2403 // public void labeledStatement() {
2404 // if (token == TT_case) {
2407 // if (token == TT_DDOT) {
2411 // throwSyntaxError("':' character after 'case' constant expected.");
2414 // } else if (token == TT_default) {
2416 // if (token == TT_DDOT) {
2420 // throwSyntaxError("':' character after 'default' expected.");
2426 // public void expressionStatement() {
2429 // private void inclusionStatement() {
2432 // public void compoundStatement() {
2435 // public void selectionStatement() {
2438 // public void iterationStatement() {
2441 // public void jumpStatement() {
2444 // public void outputStatement() {
2447 // public void scopeStatement() {
2450 // public void flowStatement() {
2453 // public void definitionStatement() {
2456 private void ifStatement() throws CoreException {
2457 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2458 if (token == TT_DDOT) {
2464 if (token == TT_DDOT) {
2468 if (token == TT_if) { //'else if'
2470 elseifStatementList();
2472 throwSyntaxError("':' expected after 'else'.");
2478 elseifStatementList();
2482 if (token != TT_endif) {
2483 throwSyntaxError("'endif' expected.");
2486 if (token != TT_SEMICOLON) {
2487 throwSyntaxError("';' expected after if-statement.");
2491 // statement [else-statement]
2493 if (token == TT_elseif) {
2495 if (token == TT_ARGOPEN) {
2498 throwSyntaxError("'(' expected after 'elseif' keyword.");
2501 if (token == TT_ARGCLOSE) {
2504 throwSyntaxError("')' expected after 'elseif' condition.");
2507 } else if (token == TT_else) {
2514 private void elseifStatementList() throws CoreException {
2520 if (token == TT_DDOT) {
2525 if (token == TT_if) { //'else if'
2528 throwSyntaxError("':' expected after 'else'.");
2541 private void elseifStatement() throws CoreException {
2542 if (token == TT_ARGOPEN) {
2545 if (token != TT_ARGOPEN) {
2546 throwSyntaxError("')' expected in else-if-statement.");
2549 if (token != TT_DDOT) {
2550 throwSyntaxError("':' expected in else-if-statement.");
2557 private void switchStatement() throws CoreException {
2558 if (token == TT_DDOT) {
2559 // ':' [labeled-statement-list] 'endswitch' ';'
2561 labeledStatementList();
2562 if (token != TT_endswitch) {
2563 throwSyntaxError("'endswitch' expected.");
2566 if (token != TT_SEMICOLON) {
2567 throwSyntaxError("';' expected after switch-statement.");
2571 // '{' [labeled-statement-list] '}'
2572 if (token != TT_LISTOPEN) {
2573 throwSyntaxError("'{' expected in switch statement.");
2576 if (token != TT_LISTCLOSE) {
2577 labeledStatementList();
2579 if (token != TT_LISTCLOSE) {
2580 throwSyntaxError("'}' expected in switch statement.");
2587 private void forStatement() throws CoreException {
2588 if (token == TT_DDOT) {
2591 if (token != TT_endfor) {
2592 throwSyntaxError("'endfor' expected.");
2595 if (token != TT_SEMICOLON) {
2596 throwSyntaxError("';' expected after for-statement.");
2604 private void whileStatement() throws CoreException {
2605 // ':' statement-list 'endwhile' ';'
2606 if (token == TT_DDOT) {
2609 if (token != TT_endwhile) {
2610 throwSyntaxError("'endwhile' expected.");
2613 if (token != TT_SEMICOLON) {
2614 throwSyntaxError("';' expected after while-statement.");
2622 private void foreachStatement() throws CoreException {
2623 if (token == TT_DDOT) {
2626 if (token != TT_endforeach) {
2627 throwSyntaxError("'endforeach' expected.");
2630 if (token != TT_SEMICOLON) {
2631 throwSyntaxError("';' expected after foreach-statement.");
2639 private void exitStatus() throws CoreException {
2640 if (token == TT_ARGOPEN) {
2643 throwSyntaxError("'(' expected in 'exit-status'.");
2645 if (token != TT_ARGCLOSE) {
2648 if (token == TT_ARGCLOSE) {
2651 throwSyntaxError("')' expected after 'exit-status'.");
2655 private void expressionList() throws CoreException {
2658 if (token == TT_COMMA) {
2666 private void expression() throws CoreException {
2667 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2670 logicalinclusiveorExpression();
2671 // while (token != TT_SEMICOLON) {
2677 private void postfixExpression() throws CoreException {
2679 boolean castFlag = false;
2694 case TT_STRING_CONSTANT :
2697 case TT_INTERPOLATED_STRING :
2702 if (token == TT_IDENTIFIER) {
2703 // check if identifier is a type:
2705 String str = identifier.toLowerCase();
2706 for (int i = 0; i < PHP_TYPES.length; i++) {
2707 if (PHP_TYPES[i].equals(str)) {
2714 if (token != TT_ARGCLOSE) {
2715 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2725 if (token != TT_ARGCLOSE) {
2726 throwSyntaxError(") expected in postfix-expression.");
2730 case TT_DOUBLE_NUMBER :
2733 case TT_INT_NUMBER :
2736 case TT_DOLLAROPEN :
2739 if (token != TT_LISTCLOSE) {
2740 throwSyntaxError("'}' expected after indirect variable token '${'.");
2747 if (token == TT_LISTOPEN) {
2750 if (token != TT_LISTCLOSE) {
2751 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2754 } else if (token == TT_ARGOPEN) {
2756 if (token != TT_ARGCLOSE) {
2758 if (token != TT_ARGCLOSE) {
2759 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2765 case TT_IDENTIFIER :
2768 if (token == TT_ARGOPEN) {
2770 if (token != TT_ARGCLOSE) {
2772 if (token != TT_ARGCLOSE) {
2773 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2782 // if (token == TT_SEMICOLON) {
2786 // throwSyntaxError("';' expected after 'print' statement.");
2793 if (token == TT_ARGOPEN) {
2795 if (token == TT_COMMA) {
2799 if (token != TT_ARGCLOSE) {
2800 throwSyntaxError("')' expected after 'list' keyword.");
2803 // if (token == TT_SET) {
2805 // logicalinclusiveorExpression();
2808 throwSyntaxError("'(' expected after 'list' keyword.");
2813 // if (token != TT_SEMICOLON) {
2816 // if (token == TT_SEMICOLON) {
2820 // throwSyntaxError("';' expected after 'exit' expression.");
2827 // if (token != TT_SEMICOLON) {
2830 // if (token == TT_SEMICOLON) {
2834 // throwSyntaxError("';' expected after 'die' expression.");
2841 // if (token == TT_ARGOPEN) {
2843 // if (token == TT_COMMA) {
2846 // expressionList();
2847 // if (token != TT_ARGCLOSE) {
2848 // throwSyntaxError("')' expected after 'list' keyword.");
2851 // if (token == TT_SET) {
2853 // logicalinclusiveorExpression();
2856 // throwSyntaxError("'(' expected after 'list' keyword.");
2860 boolean while_flag = true;
2866 if (token != TT_PARTCLOSE) {
2867 throwSyntaxError("] expected in postfix-expression.");
2871 case TT_DDOT2 : // ::
2874 if (token > TT_KEYWORD) {
2876 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2882 // if (token == TT_ARGOPEN) {
2884 // expressionList();
2885 // if (token != TT_ARGCLOSE) {
2886 // throwSyntaxError(") expected after variable '" + ident + "'.");
2891 case TT_IDENTIFIER :
2898 if (token != TT_LISTCLOSE) {
2899 throwSyntaxError("} expected in postfix-expression.");
2904 throwSyntaxError("Syntax error after '->' token.");
2905 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2906 if (token == TT_PARTOPEN) {
2909 if (token != TT_PARTCLOSE) {
2910 throwSyntaxError("] expected after '->'.");
2914 if (token == TT_ARGOPEN) {
2917 if (token != TT_ARGCLOSE) {
2918 throwSyntaxError(") expected after '->'.");
2922 if (token == TT_LISTOPEN) {
2925 if (token != TT_LISTCLOSE) {
2926 throwSyntaxError("} expected after '->'.");
2946 private void unaryExpression() throws CoreException {
2956 // '@' '&' '*' '+' '-' '~' '!'
2986 postfixExpression();
2990 private void castExpression() throws CoreException {
2991 // if (token == TT_ARGOPEN) {
2994 // if (token != TT_ARGCLOSE) {
2995 // throwSyntaxError(") expected after cast-expression.");
3002 private void typeName() throws CoreException {
3003 //'string' 'unset' 'array' 'object'
3005 //'real' 'double' 'float'
3008 if (token == TT_IDENTIFIER) {
3010 String str = identifier.toLowerCase();
3012 for (int i = 0; i < PHP_TYPES.length; i++) {
3013 if (PHP_TYPES[i].equals(str)) {
3018 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3021 private void assignExpression() throws CoreException {
3023 if (token == TT_ASSIGN) { // =
3025 logicalinclusiveorExpression();
3026 } else if (token == TT_DOTASSIGN) { // .=
3028 logicalinclusiveorExpression();
3029 } else if (token == TT_FOREACH) { // =>
3031 logicalinclusiveorExpression();
3032 } else if (token == TT_ADDTO) { // +=
3034 logicalinclusiveorExpression();
3035 } else if (token == TT_SUBTRACTFROM) { // -=
3037 logicalinclusiveorExpression();
3038 } else if (token == TT_TIMESBY) { // *=
3040 logicalinclusiveorExpression();
3041 } else if (token == TT_DIVIDEBY) { // *=
3043 logicalinclusiveorExpression();
3044 } else if (token == TT_MODASSIGN) { // %=
3046 logicalinclusiveorExpression();
3047 } else if (token == TT_ANDASSIGN) { // &=
3049 logicalinclusiveorExpression();
3050 } else if (token == TT_POWASSIGN) { // ^=
3052 logicalinclusiveorExpression();
3053 } else if (token == TT_LSHIFTASSIGN) { // <<=
3055 logicalinclusiveorExpression();
3056 } else if (token == TT_RSHIFTASSIGN) { // >>=
3058 logicalinclusiveorExpression();
3059 } else if (token == TT_TILDEASSIGN) { // ~=
3061 logicalinclusiveorExpression();
3065 private void multiplicativeExpression() throws CoreException {
3068 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3075 private void concatenationExpression() throws CoreException {
3077 multiplicativeExpression();
3078 if (token != TT_DOT) {
3085 private void additiveExpression() throws CoreException {
3087 concatenationExpression();
3088 if (token != TT_ADD && token != TT_SUBTRACT) {
3095 private void shiftExpression() throws CoreException {
3097 additiveExpression();
3098 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3105 private void relationalExpression() throws CoreException {
3108 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3115 private void identicalExpression() throws CoreException {
3117 relationalExpression();
3118 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3125 private void equalityExpression() throws CoreException {
3127 identicalExpression();
3128 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3135 private void ternaryExpression() throws CoreException {
3136 equalityExpression();
3137 if (token == TT_QUESTIONMARK) {
3140 if (token == TT_DDOT) {
3144 throwSyntaxError("':' expected in ternary operator '? :'.");
3149 private void andExpression() throws CoreException {
3151 ternaryExpression();
3152 if (token != TT_AMPERSAND) {
3159 private void exclusiveorExpression() throws CoreException {
3162 if (token != TT_POW) {
3169 private void inclusiveorExpression() throws CoreException {
3171 exclusiveorExpression();
3172 if (token != TT_LINE) {
3179 private void booleanandExpression() throws CoreException {
3181 inclusiveorExpression();
3182 if (token != TT_AND) {
3189 private void booleanorExpression() throws CoreException {
3191 booleanandExpression();
3192 if (token != TT_OR) {
3199 private void logicalandExpression() throws CoreException {
3201 booleanorExpression();
3202 if (token != TT_and) {
3209 private void logicalexclusiveorExpression() throws CoreException {
3211 logicalandExpression();
3212 if (token != TT_xor) {
3219 private void logicalinclusiveorExpression() throws CoreException {
3221 logicalexclusiveorExpression();
3222 if (token != TT_or) {
3229 // public void assignmentExpression() {
3230 // if (token == TT_VARIABLE) {
3232 // if (token == TT_SET) {
3234 // logicalinclusiveorExpression();
3237 // logicalinclusiveorExpression();
3241 private void variableList() throws CoreException {
3244 if (token == TT_COMMA) {
3252 private void variable() throws CoreException {
3253 if (token == TT_DOLLAROPEN) {
3257 if (token != TT_LISTCLOSE) {
3258 throwSyntaxError("'}' expected after indirect variable token '${'.");
3262 if (token == TT_VARIABLE) {
3264 if (token == TT_PARTOPEN) {
3267 if (token != TT_PARTCLOSE) {
3268 throwSyntaxError("']' expected in variable-list.");
3271 } else if (token == TT_ASSIGN) {
3276 throwSyntaxError("$-variable expected in variable-list.");
3281 private void constant() throws CoreException {
3287 case TT_DOUBLE_NUMBER :
3290 case TT_INT_NUMBER :
3294 throwSyntaxError("Constant expected after '+' presign.");
3300 case TT_DOUBLE_NUMBER :
3303 case TT_INT_NUMBER :
3307 throwSyntaxError("Constant expected after '-' presign.");
3319 case TT_IDENTIFIER :
3322 if (token == TT_ARGOPEN) {
3324 if (token != TT_ARGCLOSE) {
3326 if (token != TT_ARGCLOSE) {
3327 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3333 case TT_STRING_CONSTANT :
3336 case TT_INTERPOLATED_STRING :
3339 case TT_DOUBLE_NUMBER :
3342 case TT_INT_NUMBER :
3346 throwSyntaxError("Constant expected.");
3351 * Call the php parse command ( php -l -f <filename> )
3352 * and create markers according to the external parser output
3354 public static void phpExternalParse(IFile file) {
3355 //IFile file = (IFile) resource;
3356 IPath path = file.getFullPath();
3357 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3358 String filename = file.getLocation().toString();
3360 String[] arguments = { filename };
3361 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3362 String command = form.format(arguments);
3364 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3367 // parse the buffer to find the errors and warnings
3368 createMarkers(parserResult, file);
3369 } catch (CoreException e) {
3374 * Create markers according to the external parser output
3376 private static void createMarkers(String output, IFile file) throws CoreException {
3377 // delete all markers
3378 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3382 boolean flag = true;
3383 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3384 // newer php error output (tested with 4.2.3)
3385 scanLine(output, file, indx, brIndx);
3390 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3391 // older php error output (tested with 4.2.3)
3392 scanLine(output, file, indx, brIndx);
3398 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3400 String outLineNumberString;
3401 StringBuffer lineNumberBuffer = new StringBuffer(10);
3403 current = output.substring(indx, brIndx);
3405 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3406 int onLine = current.indexOf("on line <b>");
3408 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3409 for (int i = onLine; i < current.length(); i++) {
3410 ch = current.charAt(i);
3411 if ('0' <= ch && '9' >= ch) {
3412 lineNumberBuffer.append(ch);
3416 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3418 Hashtable attributes = new Hashtable();
3420 current = current.replaceAll("\n", "");
3421 current = current.replaceAll("<b>", "");
3422 current = current.replaceAll("</b>", "");
3423 MarkerUtilities.setMessage(attributes, current);
3425 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3426 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3427 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3428 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3430 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3431 MarkerUtilities.setLineNumber(attributes, lineNumber);
3432 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);