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);
201 * This method will throw the SyntaxError.
202 * It will add the good lines and columns to the Error
203 * @param error the error message
204 * @throws SyntaxError the error raised
206 private void throwSyntaxError(String error) {
208 if (str.length() < chIndx) {
211 // read until end-of-line
213 while (str.length() > eol) {
214 ch = str.charAt(eol++);
220 throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
224 * This method will throw the SyntaxError.
225 * It will add the good lines and columns to the Error
226 * @param error the error message
227 * @throws SyntaxError the error raised
229 private void throwSyntaxError(String error, int startRow) {
230 throw new SyntaxError(startRow, 0, " ", error);
234 * Method Declaration.
238 private void getChar() {
239 if (str.length() > chIndx) {
240 ch = str.charAt(chIndx++);
245 chIndx = str.length() + 1;
251 private void getNextToken_OldVersion() throws CoreException {
254 while (str.length() > chIndx) {
255 ch = str.charAt(chIndx++);
256 token = TT_UNDEFINED;
259 columnCount = chIndx;
260 continue; // while loop
262 if (str.length() == chIndx) {
265 if (!Character.isWhitespace(ch)) {
267 if (str.length() > chIndx) {
268 if (str.charAt(chIndx) == '{') {
270 token = TT_DOLLAROPEN;
277 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
281 if (ch >= '0' && ch <= '9') {
286 if (str.length() > chIndx) {
287 if (str.charAt(chIndx) == '/') {
289 // read comment until end of line:
290 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
294 } else if (str.charAt(chIndx) == '*') {
296 // multi line comment:
297 while (str.length() > chIndx) {
298 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
302 ch = str.charAt(chIndx++);
305 columnCount = chIndx;
311 } else if (ch == '#') {
312 // read comment until end of line:
313 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
317 } else if (ch == '"') {
318 // read string until end
319 boolean openString = true;
320 while (str.length() > chIndx) {
321 ch = str.charAt(chIndx++);
323 if (str.length() > chIndx) {
324 ch = str.charAt(chIndx++);
326 } else if (ch == '"') {
329 } else if (ch == '\n') {
331 columnCount = chIndx;
335 throwSyntaxError("Open string character '\"' at end of file.");
337 token = TT_INTERPOLATED_STRING;
339 } else if (ch == '\'') {
340 // read string until end
341 boolean openString = true;
342 int startRow = rowCount;
343 while (str.length() > chIndx) {
344 ch = str.charAt(chIndx++);
346 if (str.length() > chIndx) {
347 ch = str.charAt(chIndx++);
349 } else if (ch == '\'') {
352 } else if (ch == '\n') {
354 columnCount = chIndx;
358 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
360 token = TT_STRING_CONSTANT;
362 } else if (ch == '`') {
363 // read string until end
364 boolean openString = true;
365 int startRow = rowCount;
366 while (str.length() > chIndx) {
367 ch = str.charAt(chIndx++);
369 if (str.length() > chIndx) {
370 ch = str.charAt(chIndx++);
372 } else if (ch == '`') {
375 } else if (ch == '\n') {
377 columnCount = chIndx;
381 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
383 token = TT_STRING_CONSTANT;
402 token = TT_LISTCLOSE;
410 token = TT_PARTCLOSE;
418 token = TT_QUESTIONMARK;
425 if (str.length() > chIndx) {
426 if (str.charAt(chIndx) == '=') {
428 token = TT_TILDEASSIGN;
436 if (str.length() > chIndx) {
437 if (str.charAt(chIndx) == '=') {
439 token = TT_DOTASSIGN;
452 if (str.length() > chIndx) {
453 if (str.charAt(chIndx) == '=') {
455 token = TT_MODASSIGN;
462 token = TT_SEMICOLON;
467 if (str.length() > chIndx) {
468 if (str.charAt(chIndx) == '=') {
470 token = TT_POWASSIGN;
479 if (str.length() > chIndx) {
480 if (str.charAt(chIndx) == '=') {
491 if (str.length() > chIndx) {
492 if (str.charAt(chIndx) == '*') {
498 if (str.charAt(chIndx) == '=') {
509 if (str.length() > chIndx) {
510 if (str.charAt(chIndx) == '+') {
512 token = TT_INCREMENT;
516 if (str.charAt(chIndx) == '=') {
526 if (str.length() > chIndx) {
527 if (str.charAt(chIndx) == '-') {
529 token = TT_DECREMENT;
533 if (str.charAt(chIndx) == '=') {
535 token = TT_SUBTRACTFROM;
539 if (str.charAt(chIndx) == '>') {
551 if (str.length() > chIndx) {
552 ch = str.charAt(chIndx);
557 if (str.length() > chIndx) {
558 ch = str.charAt(chIndx);
579 if (str.length() > chIndx) {
580 if (str.charAt(chIndx) == '=') {
583 if (str.length() > chIndx) {
584 ch = str.charAt(chIndx);
588 token = TT_EX_UNEQUAL;
599 if (str.length() > chIndx) {
600 if (str.charAt(chIndx) == '=') {
602 token = TT_GREATEREQUAL;
605 if (str.charAt(chIndx) == '>') {
608 if (str.length() > chIndx) {
609 if (str.charAt(chIndx) == '=') {
611 token = TT_RSHIFTASSIGN;
623 if (str.length() > chIndx) {
624 if (str.charAt(chIndx) == '=') {
626 token = TT_LESSEQUAL;
630 if (str.charAt(chIndx) == '<') {
633 if (str.charAt(chIndx) == '<') {
635 int startRow = rowCount;
636 if (str.length() > chIndx) {
638 ch = str.charAt(++chIndx);
639 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
642 token = TT_STRING_CONSTANT;
643 while (str.length() > chIndx) {
644 ch = str.charAt(chIndx++);
646 if (str.length() >= chIndx + identifier.length()) {
647 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
648 chIndx += identifier.length();
656 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
657 } else if (str.charAt(chIndx) == '=') {
659 token = TT_LSHIFTASSIGN;
671 if (str.length() > chIndx) {
672 if (str.charAt(chIndx) == '|') {
682 token = TT_AMPERSAND;
683 if (str.length() > chIndx) {
684 if (str.charAt(chIndx) == '&') {
689 if (str.charAt(chIndx) == '=') {
691 token = TT_ANDASSIGN;
700 if (str.length() > chIndx) {
701 if (str.charAt(chIndx) == ':') {
716 throwSyntaxError("unexpected character: '" + ch + "'");
719 if (token == TT_UNDEFINED) {
720 throwSyntaxError("token not found");
727 chIndx = str.length() + 1;
732 if (phpList != null) {
733 if (currentPHPString < phpList.size()) {
734 token = TT_UNDEFINED;
735 temp = (PHPString) phpList.get(currentPHPString++);
736 this.str = temp.getPHPString();
739 this.rowCount = temp.getLineNumber();
740 this.columnCount = 0;
744 token = TT_UNDEFINED;
750 * gets the next token from input
752 private void getNextToken() throws CoreException {
753 boolean phpFound = false;
760 while (str.length() > chIndx) {
761 token = TT_UNDEFINED;
762 ch = str.charAt(chIndx++);
768 ch2 = str.charAt(chIndx++);
770 ch2 = str.charAt(chIndx++);
771 if (Character.isWhitespace(ch2)) {
776 } else if (ch2 == 'p' || ch2 == 'P') {
777 ch2 = str.charAt(chIndx++);
778 if (ch2 == 'h' || ch2 == 'H') {
779 ch2 = str.charAt(chIndx++);
780 if (ch2 == 'p' || ch2 == 'P') {
798 while (str.length() > chIndx) {
799 ch = str.charAt(chIndx++);
800 token = TT_UNDEFINED;
803 columnCount = chIndx;
804 continue; // while loop
806 if (str.length() == chIndx) {
809 if (!Character.isWhitespace(ch)) {
811 if (str.length() > chIndx) {
812 if (str.charAt(chIndx) == '{') {
814 token = TT_DOLLAROPEN;
821 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
825 if (ch >= '0' && ch <= '9') {
830 if (str.length() > chIndx) {
831 if (str.charAt(chIndx) == '/') {
834 // read comment until end of line:
835 while ((str.length() > chIndx) && (ch != '\n')) {
836 ch = str.charAt(chIndx++);
838 ch2 = str.charAt(chIndx);
852 } else if (str.charAt(chIndx) == '*') {
854 // multi line comment:
855 while (str.length() > chIndx) {
856 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
860 ch = str.charAt(chIndx++);
863 columnCount = chIndx;
869 } else if (ch == '#') {
870 // read comment until end of line:
871 while ((str.length() > chIndx) && (ch != '\n')) {
872 ch = str.charAt(chIndx++);
874 ch2 = str.charAt(chIndx);
888 } else if (ch == '"') {
889 getString('"',TT_INTERPOLATED_STRING,"Open string character '\"' at end of file.");
891 } else if (ch == '\'') {
892 getString('\'',TT_STRING_CONSTANT,"Open string character \"'\" at end of file.");
894 } else if (ch == '`') {
895 getString('`',TT_STRING_CONSTANT,"Open string character \"`\" at end of file.");
896 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
915 token = TT_LISTCLOSE;
923 token = TT_PARTCLOSE;
931 token = TT_QUESTIONMARK;
932 if (str.length() > chIndx) {
933 if (str.charAt(chIndx) == '>') {
949 if (str.length() > chIndx) {
950 if (str.charAt(chIndx) == '=') {
952 token = TT_TILDEASSIGN;
960 if (str.length() > chIndx) {
961 if (str.charAt(chIndx) == '=') {
963 token = TT_DOTASSIGN;
976 if (str.length() > chIndx) {
977 if (str.charAt(chIndx) == '=') {
979 token = TT_MODASSIGN;
986 token = TT_SEMICOLON;
991 if (str.length() > chIndx) {
992 if (str.charAt(chIndx) == '=') {
994 token = TT_POWASSIGN;
1003 if (str.length() > chIndx) {
1004 if (str.charAt(chIndx) == '=') {
1006 token = TT_DIVIDEBY;
1014 token = TT_MULTIPLY;
1015 if (str.length() > chIndx) {
1016 if (str.charAt(chIndx) == '*') {
1022 if (str.charAt(chIndx) == '=') {
1033 if (str.length() > chIndx) {
1034 if (str.charAt(chIndx) == '+') {
1036 token = TT_INCREMENT;
1040 if (str.charAt(chIndx) == '=') {
1049 token = TT_SUBTRACT;
1050 if (str.length() > chIndx) {
1051 if (str.charAt(chIndx) == '-') {
1053 token = TT_DECREMENT;
1057 if (str.charAt(chIndx) == '=') {
1059 token = TT_SUBTRACTFROM;
1063 if (str.charAt(chIndx) == '>') {
1075 if (str.length() > chIndx) {
1076 ch = str.charAt(chIndx);
1081 if (str.length() > chIndx) {
1082 ch = str.charAt(chIndx);
1086 token = TT_EX_EQUAL;
1103 if (str.length() > chIndx) {
1104 if (str.charAt(chIndx) == '=') {
1107 if (str.length() > chIndx) {
1108 ch = str.charAt(chIndx);
1112 token = TT_EX_UNEQUAL;
1123 if (str.length() > chIndx) {
1124 if (str.charAt(chIndx) == '=') {
1126 token = TT_GREATEREQUAL;
1129 if (str.charAt(chIndx) == '>') {
1132 if (str.length() > chIndx) {
1133 if (str.charAt(chIndx) == '=') {
1135 token = TT_RSHIFTASSIGN;
1147 if (str.length() > chIndx) {
1148 if (str.charAt(chIndx) == '=') {
1150 token = TT_LESSEQUAL;
1154 if (str.charAt(chIndx) == '<') {
1157 if (str.charAt(chIndx) == '<') {
1159 int startRow = rowCount;
1160 if (str.length() > chIndx) {
1162 ch = str.charAt(++chIndx);
1163 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1166 token = TT_STRING_CONSTANT;
1167 while (str.length() > chIndx) {
1168 ch = str.charAt(chIndx++);
1170 if (str.length() >= chIndx + identifier.length()) {
1171 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1172 chIndx += identifier.length();
1180 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1181 } else if (str.charAt(chIndx) == '=') {
1183 token = TT_LSHIFTASSIGN;
1195 if (str.length() > chIndx) {
1196 if (str.charAt(chIndx) == '|') {
1206 token = TT_AMPERSAND;
1207 if (str.length() > chIndx) {
1208 if (str.charAt(chIndx) == '&') {
1213 if (str.charAt(chIndx) == '=') {
1215 token = TT_ANDASSIGN;
1224 if (str.length() > chIndx) {
1225 if (str.charAt(chIndx) == ':') {
1240 throwSyntaxError("unexpected character: '" + ch + "'");
1243 if (token == TT_UNDEFINED) {
1244 throwSyntaxError("token not found");
1251 } catch (StringIndexOutOfBoundsException e) {
1252 // catched from charAt
1255 chIndx = str.length() + 1;
1260 // if (phpList != null) {
1261 // if (currentPHPString < phpList.size()) {
1262 // token = TT_UNDEFINED;
1263 // temp = (PHPString) phpList.get(currentPHPString++);
1264 // this.str = temp.getPHPString();
1265 // this.token = TT_EOF;
1267 // this.rowCount = temp.getLineNumber();
1268 // this.columnCount = 0;
1272 // token = TT_UNDEFINED;
1279 * Get an identifier.
1281 private void getIdentifier() {
1282 // StringBuffer ident = new StringBuffer();
1283 int startPosition = chIndx - 1;
1284 // ident.append(ch);
1287 // attention recursive call:
1289 token = TT_VARIABLE;
1292 token = TT_IDENTIFIER;
1297 //this will read the buffer until the next character is a forbidden character for identifier
1298 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1299 // ident.append(ch);
1302 int endPosition = chIndx--;
1303 int length = (--endPosition) - startPosition;
1305 identifier = str.substring(startPosition, endPosition);
1306 // System.out.println(identifier);
1308 // determine if this identitfer is a keyword
1309 // @todo improve this in future version
1310 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1312 token = i.intValue();
1318 * if it's a <code>double</code> the number will be stored in <code>doubleNumber</code> and the token will have the
1319 * value {@link PHPParser#TT_DOUBLE_NUMBER}<br />
1320 * if it's a <code>double</code> the number will be stored in <code>longNumber</code> and the token will have the
1321 * value {@link PHPParser#TT_INT_NUMBER}
1323 private void getNumber() {
1324 StringBuffer inum = new StringBuffer();
1333 // determine number conversions:
1334 if (firstCh == '0') {
1363 if (numFormat == 16) {
1364 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1369 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1370 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1371 if (ch == '.' && dFlag != ' ') {
1374 if ((dFlag == 'E') || (dFlag == 'e')) {
1380 if ((ch == '-') || (ch == '+')) {
1394 doubleNumber = new Double(inum.toString());
1395 token = TT_DOUBLE_NUMBER;
1398 longNumber = Long.valueOf(inum.toString(), numFormat);
1399 token = TT_INT_NUMBER;
1403 } catch (Throwable e) {
1404 throwSyntaxError("Number format error: " + inum.toString());
1410 * @param openChar the opening char ('\'', '"', '`')
1411 * @param typeString the type of string {@link #TT_STRING_CONSTANT},{@link #TT_INTERPOLATED_STRING}
1412 * @param errorMsg the error message in case of parse error in the string
1414 private void getString(final char openChar, final int typeString, final String errorMsg) {
1415 StringBuffer sBuffer = new StringBuffer();
1416 boolean openString = true;
1417 int startRow = rowCount;
1418 while (str.length() > chIndx) {
1419 ch = str.charAt(chIndx++);
1422 if (str.length() > chIndx) {
1423 ch = str.charAt(chIndx++);
1426 } else if (ch == openChar) {
1429 } else if (ch == '\n') {
1431 columnCount = chIndx;
1437 if (typeString == TT_STRING_CONSTANT) {
1438 throwSyntaxError(errorMsg, startRow);
1440 throwSyntaxError(errorMsg);
1444 stringValue = sBuffer.toString();
1447 public void htmlParserTester(String input) {
1449 int startLineNumber = 1;
1453 boolean phpMode = false;
1454 boolean phpFound = false;
1456 phpList = new ArrayList();
1457 currentPHPString = 0;
1461 while (i < input.length()) {
1462 ch = input.charAt(i++);
1466 if ((!phpMode) && ch == '<') {
1467 ch2 = input.charAt(i++);
1469 ch2 = input.charAt(i++);
1470 if (Character.isWhitespace(ch2)) {
1475 startLineNumber = lineNumber;
1477 } else if (ch2 == 'p') {
1478 ch2 = input.charAt(i++);
1480 ch2 = input.charAt(i++);
1485 startLineNumber = lineNumber;
1491 } else if (ch2 == 'P') {
1492 ch2 = input.charAt(i++);
1494 ch2 = input.charAt(i++);
1499 startLineNumber = lineNumber;
1512 if (ch == '/' && i < input.length()) {
1513 ch2 = input.charAt(i++);
1515 while (i < input.length()) {
1516 ch = input.charAt(i++);
1517 if (ch == '?' && i < input.length()) {
1518 ch2 = input.charAt(i++);
1522 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1526 } else if (ch == '\n') {
1532 } else if (ch2 == '*') {
1533 // multi-line comment
1534 while (i < input.length()) {
1535 ch = input.charAt(i++);
1538 } else if (ch == '*' && i < input.length()) {
1539 ch2 = input.charAt(i++);
1550 } else if (ch == '#') {
1551 while (i < input.length()) {
1552 ch = input.charAt(i++);
1553 if (ch == '?' && i < input.length()) {
1554 ch2 = input.charAt(i++);
1558 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1562 } else if (ch == '\n') {
1568 } else if (ch == '"') {
1570 while (i < input.length()) {
1571 ch = input.charAt(i++);
1574 } else if (ch == '\\' && i < input.length()) { // escape
1576 } else if (ch == '"') {
1581 } else if (ch == '\'') {
1583 while (i < input.length()) {
1584 ch = input.charAt(i++);
1587 } else if (ch == '\\' && i < input.length()) { // escape
1589 } else if (ch == '\'') {
1596 if (ch == '?' && i < input.length()) {
1597 ch2 = input.charAt(i++);
1601 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1610 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1613 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1614 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1616 // for (int j=0;j<phpList.size();j++) {
1617 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1618 // int startIndx = temp.length()-10;
1619 // if (startIndx<0) {
1622 // System.out.println(temp.substring(startIndx)+"?>");
1624 phpParserTester(null, 1);
1626 // for(int j=0;j<phpList.size();j++) {
1627 // temp = (PHPString) phpList.get(j);
1628 // parser.start(temp.getPHPString(), temp.getLineNumber());
1631 } catch (CoreException e) {
1635 public void phpParserTester(String s, int rowCount) throws CoreException {
1638 if (phpList.size() != 0) {
1639 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1642 this.token = TT_EOF;
1644 this.rowCount = rowCount;
1645 this.columnCount = 0;
1646 this.phpEnd = false;
1647 this.phpMode = true;
1651 if (token != TT_EOF && token != TT_UNDEFINED) {
1654 if (token != TT_EOF && token != TT_UNDEFINED) {
1655 if (token == TT_ARGCLOSE) {
1656 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1658 if (token == TT_LISTCLOSE) {
1659 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1661 if (token == TT_PARTCLOSE) {
1662 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1665 if (token == TT_ARGOPEN) {
1666 throwSyntaxError("Read character '('; end-of-file not reached.");
1668 if (token == TT_LISTOPEN) {
1669 throwSyntaxError("Read character '{'; end-of-file not reached.");
1671 if (token == TT_PARTOPEN) {
1672 throwSyntaxError("Read character '['; end-of-file not reached.");
1675 throwSyntaxError("End-of-file not reached.");
1678 } catch (SyntaxError err) {
1682 setMarker(err.getMessage(), err.getLine(), ERROR);
1684 // if an error occured,
1685 // try to find keywords 'class' or 'function'
1686 // to parse the rest of the string
1687 while (token != TT_EOF && token != TT_UNDEFINED) {
1688 if (token == TT_class || token == TT_function) {
1693 if (token == TT_EOF || token == TT_UNDEFINED) {
1702 * Parses a string with php tags
1703 * i.e. '<body> <?php phpinfo() ?> </body>'
1705 public void parse(String s) throws CoreException {
1707 this.token = TT_EOF;
1710 this.columnCount = 0;
1711 this.phpEnd = false;
1712 this.phpMode = false;
1716 if (token != TT_EOF && token != TT_UNDEFINED) {
1719 if (token != TT_EOF && token != TT_UNDEFINED) {
1720 if (token == TT_ARGCLOSE) {
1721 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1723 if (token == TT_LISTCLOSE) {
1724 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1726 if (token == TT_PARTCLOSE) {
1727 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1730 if (token == TT_ARGOPEN) {
1731 throwSyntaxError("Read character '('; end-of-file not reached.");
1733 if (token == TT_LISTOPEN) {
1734 throwSyntaxError("Read character '{'; end-of-file not reached.");
1736 if (token == TT_PARTOPEN) {
1737 throwSyntaxError("Read character '['; end-of-file not reached.");
1740 throwSyntaxError("End-of-file not reached.");
1743 } catch (SyntaxError sytaxErr1) {
1744 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1746 // if an error occured,
1747 // try to find keywords 'class' or 'function'
1748 // to parse the rest of the string
1749 while (token != TT_EOF && token != TT_UNDEFINED) {
1750 if (token == TT_class || token == TT_function) {
1755 if (token == TT_EOF || token == TT_UNDEFINED) {
1758 } catch (SyntaxError sytaxErr2) {
1759 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1767 public PHPOutlineInfo parseInfo(Object parent, String s) {
1768 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1769 // Stack stack = new Stack();
1770 // stack.push(outlineInfo.getDeclarations());
1773 this.token = TT_EOF;
1776 this.columnCount = 0;
1777 this.phpEnd = false;
1778 this.phpMode = false;
1782 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1783 } catch (CoreException e) {
1788 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
1789 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1790 PHPSegmentWithChildren temp;
1792 String oldIdentifier;
1793 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1795 while (token != TT_EOF && token != TT_UNDEFINED) {
1796 if (token == TT_VARIABLE) {
1797 outlineInfo.addVariable(identifier);
1799 } else if (token == TT_var) {
1801 if (token == TT_VARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1803 outlineInfo.addVariable(identifier);
1804 if (token != TT_SEMICOLON) {
1805 oldIdentifier = identifier;
1808 case TT_VARIABLE : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1810 case TT_IDENTIFIER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1812 case TT_DOUBLE_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
1814 case TT_INT_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
1816 case TT_INTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1818 case TT_STRING_CONSTANT : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1820 default : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
1824 current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1827 } else if (token == TT_function) {
1829 if (token == TT_AMPERSAND) {
1832 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1833 outlineInfo.addVariable(identifier);
1834 temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
1837 parseDeclarations(outlineInfo, temp, true);
1839 } else if (token == TT_class) {
1841 if (token == TT_IDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
1842 outlineInfo.addVariable(identifier);
1843 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1845 // stack.push(temp);
1848 //skip tokens for classname, extends and others until we have the opening '{'
1849 while (token != TT_LISTOPEN && token != TT_EOF && token != TT_UNDEFINED) {
1852 parseDeclarations(outlineInfo, temp, true);
1855 } else if (token == TT_LISTOPEN) {
1858 } else if (token == TT_LISTCLOSE) {
1861 if (counter == 0 && goBack) {
1864 } else if (token == TT_require || token == TT_require_once || token == TT_include || token == TT_include_once) {
1866 outlineInfo.addVariable(identifier);
1867 current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
1873 } catch (CoreException e) {
1874 } catch (SyntaxError sytaxErr) {
1876 setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
1877 } catch (CoreException e) {
1882 private void statementList() throws CoreException {
1885 if ((token == TT_LISTCLOSE)
1886 || (token == TT_case)
1887 || (token == TT_default)
1888 || (token == TT_elseif)
1889 || (token == TT_endif)
1890 || (token == TT_endfor)
1891 || (token == TT_endforeach)
1892 || (token == TT_endwhile)
1893 || (token == TT_endswitch)
1894 || (token == TT_EOF)
1895 || (token == TT_UNDEFINED)) {
1901 private void compoundStatement() throws CoreException {
1902 // '{' [statement-list] '}'
1903 if (token == TT_LISTOPEN) {
1906 throwSyntaxError("'{' expected in compound-statement.");
1908 if (token != TT_LISTCLOSE) {
1911 if (token == TT_LISTCLOSE) {
1914 throwSyntaxError("'}' expected in compound-statement.");
1918 private void statement() throws CoreException {
1919 // if (token > TT_KEYWORD && token != TT_list && token != TT_new) {
1920 String keyword = identifier;
1921 if (token == TT_include || token == TT_include_once) {
1924 if (token == TT_SEMICOLON) {
1928 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1933 } else if (token == TT_require || token == TT_require_once) {
1937 if (token == TT_SEMICOLON) {
1941 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1946 } else if (token == TT_if) {
1948 if (token == TT_ARGOPEN) {
1951 throwSyntaxError("'(' expected after 'if' keyword.");
1954 if (token == TT_ARGCLOSE) {
1957 throwSyntaxError("')' expected after 'if' condition.");
1962 } else if (token == TT_switch) {
1964 if (token == TT_ARGOPEN) {
1967 throwSyntaxError("'(' expected after 'switch' keyword.");
1970 if (token == TT_ARGCLOSE) {
1973 throwSyntaxError("')' expected after 'switch' condition.");
1977 } else if (token == TT_for) {
1979 if (token == TT_ARGOPEN) {
1982 throwSyntaxError("'(' expected after 'for' keyword.");
1984 if (token == TT_SEMICOLON) {
1988 if (token == TT_SEMICOLON) {
1991 throwSyntaxError("';' expected after 'for'.");
1994 if (token == TT_SEMICOLON) {
1998 if (token == TT_SEMICOLON) {
2001 throwSyntaxError("';' expected after 'for'.");
2004 if (token == TT_ARGCLOSE) {
2008 if (token == TT_ARGCLOSE) {
2011 throwSyntaxError("')' expected after 'for'.");
2016 } else if (token == TT_while) {
2018 if (token == TT_ARGOPEN) {
2021 throwSyntaxError("'(' expected after 'while' keyword.");
2024 if (token == TT_ARGCLOSE) {
2027 throwSyntaxError("')' expected after 'while' condition.");
2031 } else if (token == TT_do) {
2033 if (token == TT_LISTOPEN) {
2036 throwSyntaxError("'{' expected after 'do' keyword.");
2038 if (token != TT_LISTCLOSE) {
2041 if (token == TT_LISTCLOSE) {
2044 throwSyntaxError("'}' expected after 'do' keyword.");
2046 if (token == TT_while) {
2048 if (token == TT_ARGOPEN) {
2051 throwSyntaxError("'(' expected after 'while' keyword.");
2054 if (token == TT_ARGCLOSE) {
2057 throwSyntaxError("')' expected after 'while' condition.");
2060 throwSyntaxError("'while' expected after 'do' keyword.");
2062 if (token == TT_SEMICOLON) {
2066 throwSyntaxError("';' expected after do-while statement.");
2071 } else if (token == TT_foreach) {
2073 if (token == TT_ARGOPEN) {
2076 throwSyntaxError("'(' expected after 'foreach' keyword.");
2079 if (token == TT_as) {
2082 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2085 if (token == TT_FOREACH) {
2089 if (token == TT_ARGCLOSE) {
2092 throwSyntaxError("')' expected after 'foreach' expression.");
2097 } else if (token == TT_continue || token == TT_break || token == TT_return) {
2099 if (token != TT_SEMICOLON) {
2102 if (token == TT_SEMICOLON) {
2106 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2112 } else if (token == TT_echo) {
2115 if (token == TT_SEMICOLON) {
2119 throwSyntaxError("';' expected after 'echo' statement.");
2124 // } else if (token == TT_print) {
2127 // if (token == TT_SEMICOLON) {
2131 // throwSyntaxError("';' expected after 'print' statement.");
2137 } else if (token == TT_global || token == TT_static) {
2140 if (token == TT_SEMICOLON) {
2144 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2150 // } else if (token == TT_unset) {
2152 // if (token == TT_ARGOPEN) {
2155 // throwSyntaxError("'(' expected after 'unset' keyword.");
2158 // if (token == TT_ARGCLOSE) {
2161 // throwSyntaxError("')' expected after 'unset' statement.");
2163 // if (token == TT_SEMICOLON) {
2167 // throwSyntaxError("';' expected after 'unset' statement.");
2173 // } else if (token == TT_exit || token == TT_die) {
2175 // if (token != TT_SEMICOLON) {
2178 // if (token == TT_SEMICOLON) {
2182 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2188 } else if (token == TT_define) {
2190 if (token == TT_ARGOPEN) {
2193 throwSyntaxError("'(' expected after 'define' keyword.");
2196 if (token == TT_COMMA) {
2199 throwSyntaxError("',' expected after first 'define' constant.");
2202 if (token == TT_COMMA) {
2206 if (token == TT_ARGCLOSE) {
2209 throwSyntaxError("')' expected after 'define' statement.");
2211 if (token == TT_SEMICOLON) {
2215 throwSyntaxError("';' expected after 'define' statement.");
2220 } else if (token == TT_function) {
2222 functionDefinition();
2224 } else if (token == TT_class) {
2230 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2231 } else if (token == TT_LISTOPEN) {
2232 // compoundStatement
2234 if (token != TT_LISTCLOSE) {
2237 if (token == TT_LISTCLOSE) {
2241 throwSyntaxError("'}' expected.");
2244 if (token != TT_SEMICOLON) {
2247 if (token == TT_SEMICOLON) {
2252 throwSyntaxError("';' expected after expression.");
2259 private void classDeclarator() throws CoreException {
2261 //identifier 'extends' identifier
2262 if (token == TT_IDENTIFIER) {
2264 if (token == TT_extends) {
2266 if (token == TT_IDENTIFIER) {
2269 throwSyntaxError("Class name expected after keyword 'extends'.");
2273 throwSyntaxError("Class name expected after keyword 'class'.");
2277 private void classBody() throws CoreException {
2278 //'{' [class-element-list] '}'
2279 if (token == TT_LISTOPEN) {
2281 if (token != TT_LISTCLOSE) {
2284 if (token == TT_LISTCLOSE) {
2287 throwSyntaxError("'}' expected at end of class body.");
2290 throwSyntaxError("'{' expected at start of class body.");
2294 private void classElementList() throws CoreException {
2297 } while (token == TT_function || token == TT_var);
2300 private void classElement() throws CoreException {
2302 //function-definition
2303 if (token == TT_function) {
2305 functionDefinition();
2306 } else if (token == TT_var) {
2310 throwSyntaxError("'function' or 'var' expected.");
2314 private void classProperty() throws CoreException {
2315 //'var' variable ';'
2316 //'var' variable '=' constant ';'
2318 if (token == TT_VARIABLE) {
2320 if (token == TT_ASSIGN) {
2325 throwSyntaxError("Variable expected after keyword 'var'.");
2327 if (token != TT_COMMA) {
2332 if (token == TT_SEMICOLON) {
2335 throwSyntaxError("';' expected after variable declaration.");
2339 private void functionDefinition() throws CoreException {
2340 functionDeclarator();
2341 compoundStatement();
2344 private void functionDeclarator() throws CoreException {
2345 //identifier '(' [parameter-list] ')'
2346 if (token == TT_AMPERSAND) {
2349 if (token == TT_IDENTIFIER) {
2351 if (token == TT_ARGOPEN) {
2354 throwSyntaxError("'(' expected in function declaration.");
2356 if (token != TT_ARGCLOSE) {
2359 if (token != TT_ARGCLOSE) {
2360 throwSyntaxError("')' expected in function declaration.");
2367 private void parameterList() throws CoreException {
2368 //parameter-declaration
2369 //parameter-list ',' parameter-declaration
2371 parameterDeclaration();
2372 if (token != TT_COMMA) {
2379 private void parameterDeclaration() throws CoreException {
2381 //variable-reference
2382 if (token == TT_AMPERSAND) {
2384 if (token == TT_VARIABLE) {
2387 throwSyntaxError("Variable expected after reference operator '&'.");
2390 //variable '=' constant
2391 if (token == TT_VARIABLE) {
2393 if (token == TT_ASSIGN) {
2401 private void labeledStatementList() throws CoreException {
2402 if (token != TT_case && token != TT_default) {
2403 throwSyntaxError("'case' or 'default' expected.");
2406 if (token == TT_case) {
2409 if (token == TT_DDOT) {
2411 if (token == TT_case || token == TT_default) { // empty case statement ?
2415 } else if (token == TT_SEMICOLON) {
2416 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2418 if (token == TT_case) { // empty case statement ?
2423 throwSyntaxError("':' character after 'case' constant expected.");
2425 } else { // TT_default
2427 if (token == TT_DDOT) {
2431 throwSyntaxError("':' character after 'default' expected.");
2434 } while (token == TT_case || token == TT_default);
2437 // public void labeledStatement() {
2438 // if (token == TT_case) {
2441 // if (token == TT_DDOT) {
2445 // throwSyntaxError("':' character after 'case' constant expected.");
2448 // } else if (token == TT_default) {
2450 // if (token == TT_DDOT) {
2454 // throwSyntaxError("':' character after 'default' expected.");
2460 // public void expressionStatement() {
2463 // private void inclusionStatement() {
2466 // public void compoundStatement() {
2469 // public void selectionStatement() {
2472 // public void iterationStatement() {
2475 // public void jumpStatement() {
2478 // public void outputStatement() {
2481 // public void scopeStatement() {
2484 // public void flowStatement() {
2487 // public void definitionStatement() {
2490 private void ifStatement() throws CoreException {
2491 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2492 if (token == TT_DDOT) {
2498 if (token == TT_DDOT) {
2502 if (token == TT_if) { //'else if'
2504 elseifStatementList();
2506 throwSyntaxError("':' expected after 'else'.");
2512 elseifStatementList();
2516 if (token != TT_endif) {
2517 throwSyntaxError("'endif' expected.");
2520 if (token != TT_SEMICOLON) {
2521 throwSyntaxError("';' expected after if-statement.");
2525 // statement [else-statement]
2527 if (token == TT_elseif) {
2529 if (token == TT_ARGOPEN) {
2532 throwSyntaxError("'(' expected after 'elseif' keyword.");
2535 if (token == TT_ARGCLOSE) {
2538 throwSyntaxError("')' expected after 'elseif' condition.");
2541 } else if (token == TT_else) {
2548 private void elseifStatementList() throws CoreException {
2554 if (token == TT_DDOT) {
2559 if (token == TT_if) { //'else if'
2562 throwSyntaxError("':' expected after 'else'.");
2575 private void elseifStatement() throws CoreException {
2576 if (token == TT_ARGOPEN) {
2579 if (token != TT_ARGOPEN) {
2580 throwSyntaxError("')' expected in else-if-statement.");
2583 if (token != TT_DDOT) {
2584 throwSyntaxError("':' expected in else-if-statement.");
2591 private void switchStatement() throws CoreException {
2592 if (token == TT_DDOT) {
2593 // ':' [labeled-statement-list] 'endswitch' ';'
2595 labeledStatementList();
2596 if (token != TT_endswitch) {
2597 throwSyntaxError("'endswitch' expected.");
2600 if (token != TT_SEMICOLON) {
2601 throwSyntaxError("';' expected after switch-statement.");
2605 // '{' [labeled-statement-list] '}'
2606 if (token != TT_LISTOPEN) {
2607 throwSyntaxError("'{' expected in switch statement.");
2610 if (token != TT_LISTCLOSE) {
2611 labeledStatementList();
2613 if (token != TT_LISTCLOSE) {
2614 throwSyntaxError("'}' expected in switch statement.");
2621 private void forStatement() throws CoreException {
2622 if (token == TT_DDOT) {
2625 if (token != TT_endfor) {
2626 throwSyntaxError("'endfor' expected.");
2629 if (token != TT_SEMICOLON) {
2630 throwSyntaxError("';' expected after for-statement.");
2638 private void whileStatement() throws CoreException {
2639 // ':' statement-list 'endwhile' ';'
2640 if (token == TT_DDOT) {
2643 if (token != TT_endwhile) {
2644 throwSyntaxError("'endwhile' expected.");
2647 if (token != TT_SEMICOLON) {
2648 throwSyntaxError("';' expected after while-statement.");
2656 private void foreachStatement() throws CoreException {
2657 if (token == TT_DDOT) {
2660 if (token != TT_endforeach) {
2661 throwSyntaxError("'endforeach' expected.");
2664 if (token != TT_SEMICOLON) {
2665 throwSyntaxError("';' expected after foreach-statement.");
2673 private void exitStatus() throws CoreException {
2674 if (token == TT_ARGOPEN) {
2677 throwSyntaxError("'(' expected in 'exit-status'.");
2679 if (token != TT_ARGCLOSE) {
2682 if (token == TT_ARGCLOSE) {
2685 throwSyntaxError("')' expected after 'exit-status'.");
2689 private void expressionList() throws CoreException {
2692 if (token == TT_COMMA) {
2700 private void expression() throws CoreException {
2701 //todo: find a better way to get the expression
2702 expression = new StringBuffer();
2703 for (int i = chIndx;i<str.length();i++) {
2704 if (str.charAt(i) == ';') {
2707 expression.append(str.charAt(i));
2709 // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
2712 logicalinclusiveorExpression();
2713 // while (token != TT_SEMICOLON) {
2719 private void postfixExpression() throws CoreException {
2721 boolean castFlag = false;
2736 case TT_STRING_CONSTANT :
2739 case TT_INTERPOLATED_STRING :
2744 if (token == TT_IDENTIFIER) {
2745 // check if identifier is a type:
2747 String str = identifier.toLowerCase();
2748 for (int i = 0; i < PHP_TYPES.length; i++) {
2749 if (PHP_TYPES[i].equals(str)) {
2756 if (token != TT_ARGCLOSE) {
2757 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2767 if (token != TT_ARGCLOSE) {
2768 throwSyntaxError(") expected in postfix-expression.");
2772 case TT_DOUBLE_NUMBER :
2775 case TT_INT_NUMBER :
2778 case TT_DOLLAROPEN :
2781 if (token != TT_LISTCLOSE) {
2782 throwSyntaxError("'}' expected after indirect variable token '${'.");
2789 if (token == TT_LISTOPEN) {
2792 if (token != TT_LISTCLOSE) {
2793 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2796 } else if (token == TT_ARGOPEN) {
2798 if (token != TT_ARGCLOSE) {
2800 if (token != TT_ARGCLOSE) {
2801 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2807 case TT_IDENTIFIER :
2810 if (token == TT_ARGOPEN) {
2812 if (token != TT_ARGCLOSE) {
2814 if (token != TT_ARGCLOSE) {
2815 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2824 // if (token == TT_SEMICOLON) {
2828 // throwSyntaxError("';' expected after 'print' statement.");
2835 if (token == TT_ARGOPEN) {
2837 if (token == TT_COMMA) {
2841 if (token != TT_ARGCLOSE) {
2842 throwSyntaxError("')' expected after 'list' keyword.");
2845 // if (token == TT_SET) {
2847 // logicalinclusiveorExpression();
2850 throwSyntaxError("'(' expected after 'list' keyword.");
2855 // if (token != TT_SEMICOLON) {
2858 // if (token == TT_SEMICOLON) {
2862 // throwSyntaxError("';' expected after 'exit' expression.");
2869 // if (token != TT_SEMICOLON) {
2872 // if (token == TT_SEMICOLON) {
2876 // throwSyntaxError("';' expected after 'die' expression.");
2883 // if (token == TT_ARGOPEN) {
2885 // if (token == TT_COMMA) {
2888 // expressionList();
2889 // if (token != TT_ARGCLOSE) {
2890 // throwSyntaxError("')' expected after 'list' keyword.");
2893 // if (token == TT_SET) {
2895 // logicalinclusiveorExpression();
2898 // throwSyntaxError("'(' expected after 'list' keyword.");
2902 boolean while_flag = true;
2908 if (token != TT_PARTCLOSE) {
2909 throwSyntaxError("] expected in postfix-expression.");
2913 case TT_DDOT2 : // ::
2916 if (token > TT_KEYWORD) {
2918 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2924 // if (token == TT_ARGOPEN) {
2926 // expressionList();
2927 // if (token != TT_ARGCLOSE) {
2928 // throwSyntaxError(") expected after variable '" + ident + "'.");
2933 case TT_IDENTIFIER :
2940 if (token != TT_LISTCLOSE) {
2941 throwSyntaxError("} expected in postfix-expression.");
2946 throwSyntaxError("Syntax error after '->' token.");
2947 } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) {
2948 if (token == TT_PARTOPEN) {
2951 if (token != TT_PARTCLOSE) {
2952 throwSyntaxError("] expected after '->'.");
2956 if (token == TT_ARGOPEN) {
2959 if (token != TT_ARGCLOSE) {
2960 throwSyntaxError(") expected after '->'.");
2964 if (token == TT_LISTOPEN) {
2967 if (token != TT_LISTCLOSE) {
2968 throwSyntaxError("} expected after '->'.");
2988 private void unaryExpression() throws CoreException {
2998 // '@' '&' '*' '+' '-' '~' '!'
3028 postfixExpression();
3032 private void castExpression() throws CoreException {
3033 // if (token == TT_ARGOPEN) {
3036 // if (token != TT_ARGCLOSE) {
3037 // throwSyntaxError(") expected after cast-expression.");
3044 private void typeName() throws CoreException {
3045 //'string' 'unset' 'array' 'object'
3047 //'real' 'double' 'float'
3050 if (token == TT_IDENTIFIER) {
3052 String str = identifier.toLowerCase();
3054 for (int i = 0; i < PHP_TYPES.length; i++) {
3055 if (PHP_TYPES[i].equals(str)) {
3060 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3063 private void assignExpression() throws CoreException {
3065 if (token == TT_ASSIGN) { // =
3067 logicalinclusiveorExpression();
3068 } else if (token == TT_DOTASSIGN) { // .=
3070 logicalinclusiveorExpression();
3071 } else if (token == TT_FOREACH) { // =>
3073 logicalinclusiveorExpression();
3074 } else if (token == TT_ADDTO) { // +=
3076 logicalinclusiveorExpression();
3077 } else if (token == TT_SUBTRACTFROM) { // -=
3079 logicalinclusiveorExpression();
3080 } else if (token == TT_TIMESBY) { // *=
3082 logicalinclusiveorExpression();
3083 } else if (token == TT_DIVIDEBY) { // *=
3085 logicalinclusiveorExpression();
3086 } else if (token == TT_MODASSIGN) { // %=
3088 logicalinclusiveorExpression();
3089 } else if (token == TT_ANDASSIGN) { // &=
3091 logicalinclusiveorExpression();
3092 } else if (token == TT_POWASSIGN) { // ^=
3094 logicalinclusiveorExpression();
3095 } else if (token == TT_LSHIFTASSIGN) { // <<=
3097 logicalinclusiveorExpression();
3098 } else if (token == TT_RSHIFTASSIGN) { // >>=
3100 logicalinclusiveorExpression();
3101 } else if (token == TT_TILDEASSIGN) { // ~=
3103 logicalinclusiveorExpression();
3107 private void multiplicativeExpression() throws CoreException {
3110 if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) {
3117 private void concatenationExpression() throws CoreException {
3119 multiplicativeExpression();
3120 if (token != TT_DOT) {
3127 private void additiveExpression() throws CoreException {
3129 concatenationExpression();
3130 if (token != TT_ADD && token != TT_SUBTRACT) {
3137 private void shiftExpression() throws CoreException {
3139 additiveExpression();
3140 if (token != TT_LSHIFT && token != TT_RSHIFT) {
3147 private void relationalExpression() throws CoreException {
3150 if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) {
3157 private void identicalExpression() throws CoreException {
3159 relationalExpression();
3160 if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) {
3167 private void equalityExpression() throws CoreException {
3169 identicalExpression();
3170 if (token != TT_EQUAL && token != TT_UNEQUAL) {
3177 private void ternaryExpression() throws CoreException {
3178 equalityExpression();
3179 if (token == TT_QUESTIONMARK) {
3182 if (token == TT_DDOT) {
3186 throwSyntaxError("':' expected in ternary operator '? :'.");
3191 private void andExpression() throws CoreException {
3193 ternaryExpression();
3194 if (token != TT_AMPERSAND) {
3201 private void exclusiveorExpression() throws CoreException {
3204 if (token != TT_POW) {
3211 private void inclusiveorExpression() throws CoreException {
3213 exclusiveorExpression();
3214 if (token != TT_LINE) {
3221 private void booleanandExpression() throws CoreException {
3223 inclusiveorExpression();
3224 if (token != TT_AND) {
3231 private void booleanorExpression() throws CoreException {
3233 booleanandExpression();
3234 if (token != TT_OR) {
3241 private void logicalandExpression() throws CoreException {
3243 booleanorExpression();
3244 if (token != TT_and) {
3251 private void logicalexclusiveorExpression() throws CoreException {
3253 logicalandExpression();
3254 if (token != TT_xor) {
3261 private void logicalinclusiveorExpression() throws CoreException {
3263 logicalexclusiveorExpression();
3264 if (token != TT_or) {
3271 // public void assignmentExpression() {
3272 // if (token == TT_VARIABLE) {
3274 // if (token == TT_SET) {
3276 // logicalinclusiveorExpression();
3279 // logicalinclusiveorExpression();
3283 private void variableList() throws CoreException {
3286 if (token == TT_COMMA) {
3294 private void variable() throws CoreException {
3295 if (token == TT_DOLLAROPEN) {
3299 if (token != TT_LISTCLOSE) {
3300 throwSyntaxError("'}' expected after indirect variable token '${'.");
3304 if (token == TT_VARIABLE) {
3306 if (token == TT_PARTOPEN) {
3309 if (token != TT_PARTCLOSE) {
3310 throwSyntaxError("']' expected in variable-list.");
3313 } else if (token == TT_ASSIGN) {
3318 throwSyntaxError("$-variable expected in variable-list.");
3324 * It will look for a value (after a '=' for example)
3325 * @throws CoreException
3327 private void constant() throws CoreException {
3333 case TT_DOUBLE_NUMBER :
3336 case TT_INT_NUMBER :
3340 throwSyntaxError("Constant expected after '+' presign.");
3346 case TT_DOUBLE_NUMBER :
3349 case TT_INT_NUMBER :
3353 throwSyntaxError("Constant expected after '-' presign.");
3365 case TT_IDENTIFIER :
3368 if (token == TT_ARGOPEN) {
3370 if (token != TT_ARGCLOSE) {
3372 if (token != TT_ARGCLOSE) {
3373 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3379 case TT_STRING_CONSTANT :
3382 case TT_INTERPOLATED_STRING :
3385 case TT_DOUBLE_NUMBER :
3388 case TT_INT_NUMBER :
3392 throwSyntaxError("Constant expected.");
3397 * Call the php parse command ( php -l -f <filename> )
3398 * and create markers according to the external parser output
3400 public static void phpExternalParse(IFile file) {
3401 //IFile file = (IFile) resource;
3402 IPath path = file.getFullPath();
3403 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3404 String filename = file.getLocation().toString();
3406 String[] arguments = { filename };
3407 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3408 String command = form.format(arguments);
3410 String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
3413 // parse the buffer to find the errors and warnings
3414 createMarkers(parserResult, file);
3415 } catch (CoreException e) {
3420 * Create markers according to the external parser output
3422 private static void createMarkers(String output, IFile file) throws CoreException {
3423 // delete all markers
3424 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3428 boolean flag = true;
3429 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3430 // newer php error output (tested with 4.2.3)
3431 scanLine(output, file, indx, brIndx);
3436 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3437 // older php error output (tested with 4.2.3)
3438 scanLine(output, file, indx, brIndx);
3444 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3446 String outLineNumberString;
3447 StringBuffer lineNumberBuffer = new StringBuffer(10);
3449 current = output.substring(indx, brIndx);
3451 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3452 int onLine = current.indexOf("on line <b>");
3454 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3455 for (int i = onLine; i < current.length(); i++) {
3456 ch = current.charAt(i);
3457 if ('0' <= ch && '9' >= ch) {
3458 lineNumberBuffer.append(ch);
3462 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3464 Hashtable attributes = new Hashtable();
3466 current = current.replaceAll("\n", "");
3467 current = current.replaceAll("<b>", "");
3468 current = current.replaceAll("</b>", "");
3469 MarkerUtilities.setMessage(attributes, current);
3471 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3472 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3473 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3474 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3476 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3477 MarkerUtilities.setLineNumber(attributes, lineNumber);
3478 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);