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;
23 import org.eclipse.core.resources.IFile;
24 import org.eclipse.core.resources.IMarker;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IPath;
27 import org.eclipse.jface.preference.IPreferenceStore;
28 import org.eclipse.ui.texteditor.MarkerUtilities;
30 public class PHPParser extends PHPKeywords {
31 // strings for external parser call
32 private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
33 private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
35 public static final int ERROR = 2;
36 public static final int WARNING = 1;
37 public static final int INFO = 0;
39 private IFile fileToParse;
40 private ArrayList phpList;
42 private int currentPHPString;
43 private boolean phpEnd;
45 private static HashMap keywordMap = null;
53 // row counter for syntax errors:
55 // column counter for syntax errors:
66 private String stringValue;
68 /** Contains the current expression. */
69 private StringBuffer expression;
71 private boolean phpMode;
73 final static int TokenNameEOF = 0;
74 final static int TokenNameUNDEFINED = 1;
75 final static int TokenNameHTML = 2;
77 final static int TokenNameREMAINDER = 30;
78 final static int TokenNameNOT = 31;
79 final static int TokenNameDOT = 32;
80 final static int TokenNameXOR = 33;
81 final static int TokenNameDIVIDE = 34;
82 final static int TokenNameMULTIPLY = 35;
83 final static int TokenNameSUBTRACT = 36;
84 final static int TokenNameADD = 37;
85 final static int TokenNameEQUAL = 38;
86 final static int TokenNameUNEQUAL = 39;
87 final static int TokenNameGREATER = 40;
88 final static int TokenNameGREATEREQUAL = 41;
89 final static int TokenNameLESS = 42;
90 final static int TokenNameLESSEQUAL = 43;
91 final static int TokenNameAND = 44;
92 final static int TokenNameOR = 45;
93 final static int TokenNameHASH = 46;
94 final static int TokenNameDDOT = 47;
95 final static int TokenNameDOTASSIGN = 48;
97 final static int TokenNameASSIGN = 49;
98 final static int TokenNameREF = 50;
99 final static int TokenNameFOREACH = 51;
100 final static int TokenNameAMPERSAND = 52;
101 final static int TokenNameDOLLARLISTOPEN = 53;
102 final static int TokenNameTILDE = 54;
103 final static int TokenNameTILDEASSIGN = 55;
104 final static int TokenNameREMAINDER_EQUAL = 56;
105 final static int TokenNameXOR_EQUAL = 57;
106 final static int TokenNameRIGHT_SHIFT_EQUAL = 58;
107 final static int TokenNameLEFT_SHIFT_EQUAL = 59;
108 final static int TokenNameANDASSIGN = 60;
109 final static int TokenNameQUESTIONMARK = 61;
110 final static int TokenNameDDOT2 = 62;
111 final static int TokenNameAT = 63;
112 // final static int TokenNameHEREDOC = 64;
114 final static int TokenNameDOLLAROPEN = 127;
115 final static int TokenNameARGOPEN = 128;
116 final static int TokenNameARGCLOSE = 129;
117 final static int TokenNameLISTOPEN = 130;
118 final static int TokenNameLISTCLOSE = 131;
119 final static int TokenNamePARTOPEN = 132;
120 final static int TokenNamePARTCLOSE = 133;
121 final static int TokenNameCOMMA = 134;
123 final static int TokenNameSTRING = 136;
124 final static int TokenNameIDENTIFIER = 138;
125 final static int TokenNameDIGIT = 139;
126 final static int TokenNameSEMICOLON = 140;
127 final static int TokenNameSLOT = 141;
128 final static int TokenNameSLOTSEQUENCE = 142;
129 final static int TokenNameDECREMENT = 144;
130 final static int TokenNameINCREMENT = 145;
131 final static int TokenNameADDTO = 146;
132 final static int TokenNameDIVIDE_EQUAL = 147;
133 final static int TokenNameSUBTRACTFROM = 148;
134 final static int TokenNameTIMESBY = 149;
135 final static int TokenNameVARIABLE = 150;
136 final static int TokenNameINT_NUMBER = 151;
137 final static int TokenNameDOUBLE_NUMBER = 152;
138 final static int TokenNameINTERPOLATED_STRING = 153;
139 final static int TokenNameSTRING_CONSTANT = 154;
141 final static int TokenNameLEFT_SHIFT = 155;
142 final static int TokenNameRIGHT_SHIFT = 156;
143 final static int TokenNameEX_EQUAL = 157;
144 final static int TokenNameEX_UNEQUAL = 158;
145 final static int TokenNameLINE = 159;
146 // final static int TokenNameAT = 153; // @
151 *@param sess Description of Parameter
154 public PHPParser(IFile fileToParse) {
155 if (keywordMap == null) {
156 keywordMap = new HashMap();
157 for (int i = 0; i < PHP_KEYWORS.length; i++) {
158 keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
161 this.currentPHPString = 0;
162 this.fileToParse = fileToParse;
165 this.token = TokenNameEOF;
168 this.columnCount = 0;
175 * Create marker for the parse error
177 private void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
178 setMarker(fileToParse, message, lineNumber, errorLevel);
181 public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
183 Hashtable attributes = new Hashtable();
184 MarkerUtilities.setMessage(attributes, message);
185 switch (errorLevel) {
187 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
190 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
193 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
196 MarkerUtilities.setLineNumber(attributes, lineNumber);
197 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
202 * This method will throw the SyntaxError.
203 * It will add the good lines and columns to the Error
204 * @param error the error message
205 * @throws SyntaxError the error raised
207 private void throwSyntaxError(String error) {
209 if (str.length() < chIndx) {
212 // read until end-of-line
214 while (str.length() > eol) {
215 ch = str.charAt(eol++);
221 throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
225 * This method will throw the SyntaxError.
226 * It will add the good lines and columns to the Error
227 * @param error the error message
228 * @throws SyntaxError the error raised
230 private void throwSyntaxError(String error, int startRow) {
231 throw new SyntaxError(startRow, 0, " ", error);
235 * Method Declaration.
239 private void getChar() {
240 if (str.length() > chIndx) {
241 ch = str.charAt(chIndx++);
246 chIndx = str.length() + 1;
248 // token = TokenNameEOF;
252 private void getNextToken_OldVersion() throws CoreException {
255 while (str.length() > chIndx) {
256 ch = str.charAt(chIndx++);
257 token = TokenNameUNDEFINED;
260 columnCount = chIndx;
261 continue; // while loop
263 if (str.length() == chIndx) {
266 if (!Character.isWhitespace(ch)) {
268 if (str.length() > chIndx) {
269 if (str.charAt(chIndx) == '{') {
271 token = TokenNameDOLLAROPEN;
278 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
282 if (ch >= '0' && ch <= '9') {
287 if (str.length() > chIndx) {
288 if (str.charAt(chIndx) == '/') {
290 // read comment until end of line:
291 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
295 } else if (str.charAt(chIndx) == '*') {
297 // multi line comment:
298 while (str.length() > chIndx) {
299 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
303 ch = str.charAt(chIndx++);
306 columnCount = chIndx;
312 } else if (ch == '#') {
313 // read comment until end of line:
314 while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) {
318 } else if (ch == '"') {
319 // read string until end
320 boolean openString = true;
321 while (str.length() > chIndx) {
322 ch = str.charAt(chIndx++);
324 if (str.length() > chIndx) {
325 ch = str.charAt(chIndx++);
327 } else if (ch == '"') {
330 } else if (ch == '\n') {
332 columnCount = chIndx;
336 throwSyntaxError("Open string character '\"' at end of file.");
338 token = TokenNameINTERPOLATED_STRING;
340 } else if (ch == '\'') {
341 // read string until end
342 boolean openString = true;
343 int startRow = rowCount;
344 while (str.length() > chIndx) {
345 ch = str.charAt(chIndx++);
347 if (str.length() > chIndx) {
348 ch = str.charAt(chIndx++);
350 } else if (ch == '\'') {
353 } else if (ch == '\n') {
355 columnCount = chIndx;
359 throwSyntaxError("Open string character \"'\" at end of file.", startRow);
361 token = TokenNameSTRING_CONSTANT;
363 } else if (ch == '`') {
364 // read string until end
365 boolean openString = true;
366 int startRow = rowCount;
367 while (str.length() > chIndx) {
368 ch = str.charAt(chIndx++);
370 if (str.length() > chIndx) {
371 ch = str.charAt(chIndx++);
373 } else if (ch == '`') {
376 } else if (ch == '\n') {
378 columnCount = chIndx;
382 throwSyntaxError("Open string character \"`\" at end of file.", startRow);
384 token = TokenNameSTRING_CONSTANT;
391 token = TokenNameARGOPEN;
395 token = TokenNameARGCLOSE;
399 token = TokenNameLISTOPEN;
403 token = TokenNameLISTCLOSE;
407 token = TokenNamePARTOPEN;
411 token = TokenNamePARTCLOSE;
415 token = TokenNameCOMMA;
419 token = TokenNameQUESTIONMARK;
425 token = TokenNameTILDE;
426 if (str.length() > chIndx) {
427 if (str.charAt(chIndx) == '=') {
429 token = TokenNameTILDEASSIGN;
436 token = TokenNameDOT;
437 if (str.length() > chIndx) {
438 if (str.charAt(chIndx) == '=') {
440 token = TokenNameDOTASSIGN;
448 token = TokenNameSTRING;
452 token = TokenNameREMAINDER;
453 if (str.length() > chIndx) {
454 if (str.charAt(chIndx) == '=') {
456 token = TokenNameREMAINDER_EQUAL;
463 token = TokenNameSEMICOLON;
467 token = TokenNameXOR;
468 if (str.length() > chIndx) {
469 if (str.charAt(chIndx) == '=') {
471 token = TokenNameXOR_EQUAL;
478 token = TokenNameDIVIDE;
480 if (str.length() > chIndx) {
481 if (str.charAt(chIndx) == '=') {
483 token = TokenNameDIVIDE_EQUAL;
491 token = TokenNameMULTIPLY;
492 if (str.length() > chIndx) {
493 if (str.charAt(chIndx) == '*') {
495 token = TokenNameXOR;
499 if (str.charAt(chIndx) == '=') {
501 token = TokenNameTIMESBY;
509 token = TokenNameADD;
510 if (str.length() > chIndx) {
511 if (str.charAt(chIndx) == '+') {
513 token = TokenNameINCREMENT;
517 if (str.charAt(chIndx) == '=') {
519 token = TokenNameADDTO;
526 token = TokenNameSUBTRACT;
527 if (str.length() > chIndx) {
528 if (str.charAt(chIndx) == '-') {
530 token = TokenNameDECREMENT;
534 if (str.charAt(chIndx) == '=') {
536 token = TokenNameSUBTRACTFROM;
540 if (str.charAt(chIndx) == '>') {
542 token = TokenNameREF;
550 token = TokenNameASSIGN;
552 if (str.length() > chIndx) {
553 ch = str.charAt(chIndx);
557 token = TokenNameEQUAL;
558 if (str.length() > chIndx) {
559 ch = str.charAt(chIndx);
563 token = TokenNameEX_EQUAL;
570 token = TokenNameFOREACH;
578 token = TokenNameNOT;
580 if (str.length() > chIndx) {
581 if (str.charAt(chIndx) == '=') {
583 token = TokenNameUNEQUAL;
584 if (str.length() > chIndx) {
585 ch = str.charAt(chIndx);
589 token = TokenNameEX_UNEQUAL;
598 token = TokenNameGREATER;
600 if (str.length() > chIndx) {
601 if (str.charAt(chIndx) == '=') {
603 token = TokenNameGREATEREQUAL;
606 if (str.charAt(chIndx) == '>') {
608 token = TokenNameRIGHT_SHIFT;
609 if (str.length() > chIndx) {
610 if (str.charAt(chIndx) == '=') {
612 token = TokenNameRIGHT_SHIFT_EQUAL;
622 token = TokenNameLESS;
624 if (str.length() > chIndx) {
625 if (str.charAt(chIndx) == '=') {
627 token = TokenNameLESSEQUAL;
631 if (str.charAt(chIndx) == '<') {
633 token = TokenNameLEFT_SHIFT;
634 if (str.charAt(chIndx) == '<') {
636 int startRow = rowCount;
637 if (str.length() > chIndx) {
639 ch = str.charAt(++chIndx);
640 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
643 token = TokenNameSTRING_CONSTANT;
644 while (str.length() > chIndx) {
645 ch = str.charAt(chIndx++);
647 if (str.length() >= chIndx + identifier.length()) {
648 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
649 chIndx += identifier.length();
657 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
658 } else if (str.charAt(chIndx) == '=') {
660 token = TokenNameLEFT_SHIFT_EQUAL;
670 token = TokenNameLINE;
672 if (str.length() > chIndx) {
673 if (str.charAt(chIndx) == '|') {
683 token = TokenNameAMPERSAND;
684 if (str.length() > chIndx) {
685 if (str.charAt(chIndx) == '&') {
687 token = TokenNameAND;
690 if (str.charAt(chIndx) == '=') {
692 token = TokenNameANDASSIGN;
700 token = TokenNameDDOT;
701 if (str.length() > chIndx) {
702 if (str.charAt(chIndx) == ':') {
704 token = TokenNameDDOT2;
709 token = TokenNameHASH;
713 // token = TokenNameAT;
717 throwSyntaxError("unexpected character: '" + ch + "'");
720 if (token == TokenNameUNDEFINED) {
721 throwSyntaxError("token not found");
728 chIndx = str.length() + 1;
730 token = TokenNameEOF;
733 if (phpList != null) {
734 if (currentPHPString < phpList.size()) {
735 token = TokenNameUNDEFINED;
736 temp = (PHPString) phpList.get(currentPHPString++);
737 this.str = temp.getPHPString();
738 this.token = TokenNameEOF;
740 this.rowCount = temp.getLineNumber();
741 this.columnCount = 0;
745 token = TokenNameUNDEFINED;
751 * gets the next token from input
753 private void getNextToken() throws CoreException {
754 boolean phpFound = false;
761 while (str.length() > chIndx) {
762 token = TokenNameUNDEFINED;
763 ch = str.charAt(chIndx++);
769 ch2 = str.charAt(chIndx++);
771 ch2 = str.charAt(chIndx++);
772 if (Character.isWhitespace(ch2)) {
777 } else if (ch2 == 'p' || ch2 == 'P') {
778 ch2 = str.charAt(chIndx++);
779 if (ch2 == 'h' || ch2 == 'H') {
780 ch2 = str.charAt(chIndx++);
781 if (ch2 == 'p' || ch2 == 'P') {
799 while (str.length() > chIndx) {
800 ch = str.charAt(chIndx++);
801 token = TokenNameUNDEFINED;
804 columnCount = chIndx;
805 continue; // while loop
807 if (str.length() == chIndx) {
810 if (!Character.isWhitespace(ch)) {
812 if (str.length() > chIndx) {
813 if (str.charAt(chIndx) == '{') {
815 token = TokenNameDOLLAROPEN;
822 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) {
826 if (ch >= '0' && ch <= '9') {
831 if (str.length() > chIndx) {
832 if (str.charAt(chIndx) == '/') {
835 // read comment until end of line:
836 while ((str.length() > chIndx) && (ch != '\n')) {
837 ch = str.charAt(chIndx++);
839 ch2 = str.charAt(chIndx);
842 token = TokenNameHTML;
853 } else if (str.charAt(chIndx) == '*') {
855 // multi line comment:
856 while (str.length() > chIndx) {
857 if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') {
861 ch = str.charAt(chIndx++);
864 columnCount = chIndx;
870 } else if (ch == '#') {
871 // read comment until end of line:
872 while ((str.length() > chIndx) && (ch != '\n')) {
873 ch = str.charAt(chIndx++);
875 ch2 = str.charAt(chIndx);
878 token = TokenNameHTML;
889 } else if (ch == '"') {
890 getString('"',TokenNameINTERPOLATED_STRING,"Open string character '\"' at end of file.");
892 } else if (ch == '\'') {
893 getString('\'',TokenNameSTRING_CONSTANT,"Open string character \"'\" at end of file.");
895 } else if (ch == '`') {
896 getString('`',TokenNameSTRING_CONSTANT,"Open string character \"`\" at end of file.");
897 setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
904 token = TokenNameARGOPEN;
908 token = TokenNameARGCLOSE;
912 token = TokenNameLISTOPEN;
916 token = TokenNameLISTCLOSE;
920 token = TokenNamePARTOPEN;
924 token = TokenNamePARTCLOSE;
928 token = TokenNameCOMMA;
932 token = TokenNameQUESTIONMARK;
933 if (str.length() > chIndx) {
934 if (str.charAt(chIndx) == '>') {
936 token = TokenNameHTML;
949 token = TokenNameTILDE;
950 if (str.length() > chIndx) {
951 if (str.charAt(chIndx) == '=') {
953 token = TokenNameTILDEASSIGN;
960 token = TokenNameDOT;
961 if (str.length() > chIndx) {
962 if (str.charAt(chIndx) == '=') {
964 token = TokenNameDOTASSIGN;
972 token = TokenNameSTRING;
976 token = TokenNameREMAINDER;
977 if (str.length() > chIndx) {
978 if (str.charAt(chIndx) == '=') {
980 token = TokenNameREMAINDER_EQUAL;
987 token = TokenNameSEMICOLON;
991 token = TokenNameXOR;
992 if (str.length() > chIndx) {
993 if (str.charAt(chIndx) == '=') {
995 token = TokenNameXOR_EQUAL;
1002 token = TokenNameDIVIDE;
1004 if (str.length() > chIndx) {
1005 if (str.charAt(chIndx) == '=') {
1007 token = TokenNameDIVIDE_EQUAL;
1015 token = TokenNameMULTIPLY;
1016 if (str.length() > chIndx) {
1017 if (str.charAt(chIndx) == '*') {
1019 token = TokenNameXOR;
1023 if (str.charAt(chIndx) == '=') {
1025 token = TokenNameTIMESBY;
1033 token = TokenNameADD;
1034 if (str.length() > chIndx) {
1035 if (str.charAt(chIndx) == '+') {
1037 token = TokenNameINCREMENT;
1041 if (str.charAt(chIndx) == '=') {
1043 token = TokenNameADDTO;
1050 token = TokenNameSUBTRACT;
1051 if (str.length() > chIndx) {
1052 if (str.charAt(chIndx) == '-') {
1054 token = TokenNameDECREMENT;
1058 if (str.charAt(chIndx) == '=') {
1060 token = TokenNameSUBTRACTFROM;
1064 if (str.charAt(chIndx) == '>') {
1066 token = TokenNameREF;
1074 token = TokenNameASSIGN;
1076 if (str.length() > chIndx) {
1077 ch = str.charAt(chIndx);
1081 token = TokenNameEQUAL;
1082 if (str.length() > chIndx) {
1083 ch = str.charAt(chIndx);
1087 token = TokenNameEX_EQUAL;
1094 token = TokenNameFOREACH;
1102 token = TokenNameNOT;
1104 if (str.length() > chIndx) {
1105 if (str.charAt(chIndx) == '=') {
1107 token = TokenNameUNEQUAL;
1108 if (str.length() > chIndx) {
1109 ch = str.charAt(chIndx);
1113 token = TokenNameEX_UNEQUAL;
1122 token = TokenNameGREATER;
1124 if (str.length() > chIndx) {
1125 if (str.charAt(chIndx) == '=') {
1127 token = TokenNameGREATEREQUAL;
1130 if (str.charAt(chIndx) == '>') {
1132 token = TokenNameRIGHT_SHIFT;
1133 if (str.length() > chIndx) {
1134 if (str.charAt(chIndx) == '=') {
1136 token = TokenNameRIGHT_SHIFT_EQUAL;
1146 token = TokenNameLESS;
1148 if (str.length() > chIndx) {
1149 if (str.charAt(chIndx) == '=') {
1151 token = TokenNameLESSEQUAL;
1155 if (str.charAt(chIndx) == '<') {
1157 token = TokenNameLEFT_SHIFT;
1158 if (str.charAt(chIndx) == '<') {
1160 int startRow = rowCount;
1161 if (str.length() > chIndx) {
1163 ch = str.charAt(++chIndx);
1164 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
1167 token = TokenNameSTRING_CONSTANT;
1168 while (str.length() > chIndx) {
1169 ch = str.charAt(chIndx++);
1171 if (str.length() >= chIndx + identifier.length()) {
1172 if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
1173 chIndx += identifier.length();
1181 throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
1182 } else if (str.charAt(chIndx) == '=') {
1184 token = TokenNameLEFT_SHIFT_EQUAL;
1194 token = TokenNameLINE;
1196 if (str.length() > chIndx) {
1197 if (str.charAt(chIndx) == '|') {
1199 token = TokenNameOR;
1207 token = TokenNameAMPERSAND;
1208 if (str.length() > chIndx) {
1209 if (str.charAt(chIndx) == '&') {
1211 token = TokenNameAND;
1214 if (str.charAt(chIndx) == '=') {
1216 token = TokenNameANDASSIGN;
1224 token = TokenNameDDOT;
1225 if (str.length() > chIndx) {
1226 if (str.charAt(chIndx) == ':') {
1228 token = TokenNameDDOT2;
1233 token = TokenNameHASH;
1237 // token = TokenNameAT;
1241 throwSyntaxError("unexpected character: '" + ch + "'");
1244 if (token == TokenNameUNDEFINED) {
1245 throwSyntaxError("token not found");
1252 } catch (StringIndexOutOfBoundsException e) {
1253 // catched from charAt
1256 chIndx = str.length() + 1;
1258 token = TokenNameEOF;
1261 // if (phpList != null) {
1262 // if (currentPHPString < phpList.size()) {
1263 // token = TokenNameUNDEFINED;
1264 // temp = (PHPString) phpList.get(currentPHPString++);
1265 // this.str = temp.getPHPString();
1266 // this.token = TokenNameEOF;
1268 // this.rowCount = temp.getLineNumber();
1269 // this.columnCount = 0;
1273 // token = TokenNameUNDEFINED;
1280 * Get an identifier.
1282 private void getIdentifier() {
1283 // StringBuffer ident = new StringBuffer();
1284 int startPosition = chIndx - 1;
1285 // ident.append(ch);
1288 // attention recursive call:
1290 token = TokenNameVARIABLE;
1293 token = TokenNameIDENTIFIER;
1298 //this will read the buffer until the next character is a forbidden character for identifier
1299 while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) {
1300 // ident.append(ch);
1303 int endPosition = chIndx--;
1304 int length = (--endPosition) - startPosition;
1306 identifier = str.substring(startPosition, endPosition);
1307 // System.out.println(identifier);
1309 // determine if this identitfer is a keyword
1310 // @todo improve this in future version
1311 Integer i = (Integer) keywordMap.get(identifier.toLowerCase());
1313 token = i.intValue();
1319 * if it's a <code>double</code> the number will be stored in <code>doubleNumber</code> and the token will have the
1320 * value {@link PHPParser#TokenNameDOUBLE_NUMBER}<br />
1321 * if it's a <code>double</code> the number will be stored in <code>longNumber</code> and the token will have the
1322 * value {@link PHPParser#TokenNameINT_NUMBER}
1324 private void getNumber() {
1325 StringBuffer inum = new StringBuffer();
1334 // determine number conversions:
1335 if (firstCh == '0') {
1364 if (numFormat == 16) {
1365 while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
1370 while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) {
1371 if ((ch == '.') || (ch == 'E') || (ch == 'e')) {
1372 if (ch == '.' && dFlag != ' ') {
1375 if ((dFlag == 'E') || (dFlag == 'e')) {
1381 if ((ch == '-') || (ch == '+')) {
1395 doubleNumber = new Double(inum.toString());
1396 token = TokenNameDOUBLE_NUMBER;
1399 longNumber = Long.valueOf(inum.toString(), numFormat);
1400 token = TokenNameINT_NUMBER;
1404 } catch (Throwable e) {
1405 throwSyntaxError("Number format error: " + inum.toString());
1411 * @param openChar the opening char ('\'', '"', '`')
1412 * @param typeString the type of string {@link #TokenNameSTRING_CONSTANT},{@link #TokenNameINTERPOLATED_STRING}
1413 * @param errorMsg the error message in case of parse error in the string
1415 private void getString(final char openChar, final int typeString, final String errorMsg) {
1416 StringBuffer sBuffer = new StringBuffer();
1417 boolean openString = true;
1418 int startRow = rowCount;
1419 while (str.length() > chIndx) {
1420 ch = str.charAt(chIndx++);
1423 if (str.length() > chIndx) {
1424 ch = str.charAt(chIndx++);
1427 } else if (ch == openChar) {
1430 } else if (ch == '\n') {
1432 columnCount = chIndx;
1438 if (typeString == TokenNameSTRING_CONSTANT) {
1439 throwSyntaxError(errorMsg, startRow);
1441 throwSyntaxError(errorMsg);
1445 stringValue = sBuffer.toString();
1448 public void htmlParserTester(String input) {
1450 int startLineNumber = 1;
1454 boolean phpMode = false;
1455 boolean phpFound = false;
1457 phpList = new ArrayList();
1458 currentPHPString = 0;
1462 while (i < input.length()) {
1463 ch = input.charAt(i++);
1467 if ((!phpMode) && ch == '<') {
1468 ch2 = input.charAt(i++);
1470 ch2 = input.charAt(i++);
1471 if (Character.isWhitespace(ch2)) {
1476 startLineNumber = lineNumber;
1478 } else if (ch2 == 'p') {
1479 ch2 = input.charAt(i++);
1481 ch2 = input.charAt(i++);
1486 startLineNumber = lineNumber;
1492 } else if (ch2 == 'P') {
1493 ch2 = input.charAt(i++);
1495 ch2 = input.charAt(i++);
1500 startLineNumber = lineNumber;
1513 if (ch == '/' && i < input.length()) {
1514 ch2 = input.charAt(i++);
1516 while (i < input.length()) {
1517 ch = input.charAt(i++);
1518 if (ch == '?' && i < input.length()) {
1519 ch2 = input.charAt(i++);
1523 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1527 } else if (ch == '\n') {
1533 } else if (ch2 == '*') {
1534 // multi-line comment
1535 while (i < input.length()) {
1536 ch = input.charAt(i++);
1539 } else if (ch == '*' && i < input.length()) {
1540 ch2 = input.charAt(i++);
1551 } else if (ch == '#') {
1552 while (i < input.length()) {
1553 ch = input.charAt(i++);
1554 if (ch == '?' && i < input.length()) {
1555 ch2 = input.charAt(i++);
1559 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1563 } else if (ch == '\n') {
1569 } else if (ch == '"') {
1571 while (i < input.length()) {
1572 ch = input.charAt(i++);
1575 } else if (ch == '\\' && i < input.length()) { // escape
1577 } else if (ch == '"') {
1582 } else if (ch == '\'') {
1584 while (i < input.length()) {
1585 ch = input.charAt(i++);
1588 } else if (ch == '\\' && i < input.length()) { // escape
1590 } else if (ch == '\'') {
1597 if (ch == '?' && i < input.length()) {
1598 ch2 = input.charAt(i++);
1602 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1611 setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
1614 setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO);
1615 phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
1617 // for (int j=0;j<phpList.size();j++) {
1618 // String temp = ((PHPString)phpList.get(j)).getPHPString();
1619 // int startIndx = temp.length()-10;
1620 // if (startIndx<0) {
1623 // System.out.println(temp.substring(startIndx)+"?>");
1625 phpParserTester(null, 1);
1627 // for(int j=0;j<phpList.size();j++) {
1628 // temp = (PHPString) phpList.get(j);
1629 // parser.start(temp.getPHPString(), temp.getLineNumber());
1632 } catch (CoreException e) {
1636 public void phpParserTester(String s, int rowCount) throws CoreException {
1639 if (phpList.size() != 0) {
1640 this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
1643 this.token = TokenNameEOF;
1645 this.rowCount = rowCount;
1646 this.columnCount = 0;
1647 this.phpEnd = false;
1648 this.phpMode = true;
1652 if (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1655 if (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1656 if (token == TokenNameARGCLOSE) {
1657 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1659 if (token == TokenNameLISTCLOSE) {
1660 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1662 if (token == TokenNamePARTCLOSE) {
1663 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1666 if (token == TokenNameARGOPEN) {
1667 throwSyntaxError("Read character '('; end-of-file not reached.");
1669 if (token == TokenNameLISTOPEN) {
1670 throwSyntaxError("Read character '{'; end-of-file not reached.");
1672 if (token == TokenNamePARTOPEN) {
1673 throwSyntaxError("Read character '['; end-of-file not reached.");
1676 throwSyntaxError("End-of-file not reached.");
1679 } catch (SyntaxError err) {
1683 setMarker(err.getMessage(), err.getLine(), ERROR);
1685 // if an error occured,
1686 // try to find keywords 'class' or 'function'
1687 // to parse the rest of the string
1688 while (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1689 if (token == TokenNameclass || token == TokenNamefunction) {
1694 if (token == TokenNameEOF || token == TokenNameUNDEFINED) {
1703 * Parses a string with php tags
1704 * i.e. '<body> <?php phpinfo() ?> </body>'
1706 public void parse(String s) throws CoreException {
1708 this.token = TokenNameEOF;
1711 this.columnCount = 0;
1712 this.phpEnd = false;
1713 this.phpMode = false;
1717 if (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1720 if (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1721 if (token == TokenNameARGCLOSE) {
1722 throwSyntaxError("Too many closing ')'; end-of-file not reached.");
1724 if (token == TokenNameLISTCLOSE) {
1725 throwSyntaxError("Too many closing '}'; end-of-file not reached.");
1727 if (token == TokenNamePARTCLOSE) {
1728 throwSyntaxError("Too many closing ']'; end-of-file not reached.");
1731 if (token == TokenNameARGOPEN) {
1732 throwSyntaxError("Read character '('; end-of-file not reached.");
1734 if (token == TokenNameLISTOPEN) {
1735 throwSyntaxError("Read character '{'; end-of-file not reached.");
1737 if (token == TokenNamePARTOPEN) {
1738 throwSyntaxError("Read character '['; end-of-file not reached.");
1741 throwSyntaxError("End-of-file not reached.");
1744 } catch (SyntaxError sytaxErr1) {
1745 setMarker(sytaxErr1.getMessage(), sytaxErr1.getLine(), ERROR);
1747 // if an error occured,
1748 // try to find keywords 'class' or 'function'
1749 // to parse the rest of the string
1750 while (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1751 if (token == TokenNameclass || token == TokenNamefunction) {
1756 if (token == TokenNameEOF || token == TokenNameUNDEFINED) {
1759 } catch (SyntaxError sytaxErr2) {
1760 setMarker(sytaxErr2.getMessage(), sytaxErr2.getLine(), ERROR);
1768 public PHPOutlineInfo parseInfo(Object parent, String s) {
1769 PHPOutlineInfo outlineInfo = new PHPOutlineInfo(parent);
1770 // Stack stack = new Stack();
1771 // stack.push(outlineInfo.getDeclarations());
1774 this.token = TokenNameEOF;
1777 this.columnCount = 0;
1778 this.phpEnd = false;
1779 this.phpMode = false;
1783 parseDeclarations(outlineInfo, outlineInfo.getDeclarations(), false);
1784 } catch (CoreException e) {
1789 private void parseDeclarations(PHPOutlineInfo outlineInfo, PHPSegmentWithChildren current, boolean goBack) {
1790 // PHPClassDeclaration current = (PHPClassDeclaration) stack.peek();
1791 PHPSegmentWithChildren temp;
1793 String oldIdentifier;
1794 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
1796 while (token != TokenNameEOF && token != TokenNameUNDEFINED) {
1797 if (token == TokenNameVARIABLE) {
1798 outlineInfo.addVariable(identifier);
1800 } else if (token == TokenNamevar) {
1802 if (token == TokenNameVARIABLE && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_VAR)) {
1804 outlineInfo.addVariable(identifier);
1805 if (token != TokenNameSEMICOLON) {
1806 oldIdentifier = identifier;
1809 case TokenNameVARIABLE : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1811 case TokenNameIDENTIFIER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),identifier));
1813 case TokenNameDOUBLE_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier + doubleNumber, chIndx - identifier.length(),doubleNumber.toString()));
1815 case TokenNameINT_NUMBER : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),longNumber.toString()));
1817 case TokenNameINTERPOLATED_STRING : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1819 case TokenNameSTRING_CONSTANT : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length(),stringValue));
1821 default : current.add(new PHPVarDeclaration(current, oldIdentifier, chIndx - identifier.length()));
1825 current.add(new PHPVarDeclaration(current, identifier, chIndx - identifier.length()));
1828 } else if (token == TokenNamefunction) {
1830 if (token == TokenNameAMPERSAND) {
1833 if (token == TokenNameIDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_FUNC)) {
1834 outlineInfo.addVariable(identifier);
1835 temp = new PHPFunctionDeclaration(current, identifier, chIndx - identifier.length());
1838 parseDeclarations(outlineInfo, temp, true);
1840 } else if (token == TokenNameclass) {
1842 if (token == TokenNameIDENTIFIER && store.getBoolean(PHPeclipsePlugin.PHP_OUTLINE_CLASS)) {
1843 outlineInfo.addVariable(identifier);
1844 temp = new PHPClassDeclaration(current, identifier, chIndx - identifier.length());
1846 // stack.push(temp);
1849 //skip tokens for classname, extends and others until we have the opening '{'
1850 while (token != TokenNameLISTOPEN && token != TokenNameEOF && token != TokenNameUNDEFINED) {
1853 parseDeclarations(outlineInfo, temp, true);
1856 } else if (token == TokenNameLISTOPEN) {
1859 } else if (token == TokenNameLISTCLOSE) {
1862 if (counter == 0 && goBack) {
1865 } else if (token == TokenNamerequire || token == TokenNamerequire_once || token == TokenNameinclude || token == TokenNameinclude_once) {
1867 outlineInfo.addVariable(identifier);
1868 current.add(new PHPReqIncDeclaration(current, identifier, chIndx - identifier.length(),expression.toString()));
1874 } catch (CoreException e) {
1875 } catch (SyntaxError sytaxErr) {
1877 setMarker(sytaxErr.getMessage(), sytaxErr.getLine(), ERROR);
1878 } catch (CoreException e) {
1883 private void statementList() throws CoreException {
1886 if ((token == TokenNameLISTCLOSE)
1887 || (token == TokenNamecase)
1888 || (token == TokenNamedefault)
1889 || (token == TokenNameelseif)
1890 || (token == TokenNameendif)
1891 || (token == TokenNameendfor)
1892 || (token == TokenNameendforeach)
1893 || (token == TokenNameendwhile)
1894 || (token == TokenNameendswitch)
1895 || (token == TokenNameEOF)
1896 || (token == TokenNameUNDEFINED)) {
1902 private void compoundStatement() throws CoreException {
1903 // '{' [statement-list] '}'
1904 if (token == TokenNameLISTOPEN) {
1907 throwSyntaxError("'{' expected in compound-statement.");
1909 if (token != TokenNameLISTCLOSE) {
1912 if (token == TokenNameLISTCLOSE) {
1915 throwSyntaxError("'}' expected in compound-statement.");
1919 private void statement() throws CoreException {
1920 // if (token > TokenNameKEYWORD && token != TokenNamelist && token != TokenNamenew) {
1921 String keyword = identifier;
1922 if (token == TokenNameinclude || token == TokenNameinclude_once) {
1925 if (token == TokenNameSEMICOLON) {
1929 throwSyntaxError("';' character after 'include' or 'include_once' expected.");
1934 } else if (token == TokenNamerequire || token == TokenNamerequire_once) {
1938 if (token == TokenNameSEMICOLON) {
1942 throwSyntaxError("';' character after 'require' or 'require_once' expected.");
1947 } else if (token == TokenNameif) {
1949 if (token == TokenNameARGOPEN) {
1952 throwSyntaxError("'(' expected after 'if' keyword.");
1955 if (token == TokenNameARGCLOSE) {
1958 throwSyntaxError("')' expected after 'if' condition.");
1963 } else if (token == TokenNameswitch) {
1965 if (token == TokenNameARGOPEN) {
1968 throwSyntaxError("'(' expected after 'switch' keyword.");
1971 if (token == TokenNameARGCLOSE) {
1974 throwSyntaxError("')' expected after 'switch' condition.");
1978 } else if (token == TokenNamefor) {
1980 if (token == TokenNameARGOPEN) {
1983 throwSyntaxError("'(' expected after 'for' keyword.");
1985 if (token == TokenNameSEMICOLON) {
1989 if (token == TokenNameSEMICOLON) {
1992 throwSyntaxError("';' expected after 'for'.");
1995 if (token == TokenNameSEMICOLON) {
1999 if (token == TokenNameSEMICOLON) {
2002 throwSyntaxError("';' expected after 'for'.");
2005 if (token == TokenNameARGCLOSE) {
2009 if (token == TokenNameARGCLOSE) {
2012 throwSyntaxError("')' expected after 'for'.");
2017 } else if (token == TokenNamewhile) {
2019 if (token == TokenNameARGOPEN) {
2022 throwSyntaxError("'(' expected after 'while' keyword.");
2025 if (token == TokenNameARGCLOSE) {
2028 throwSyntaxError("')' expected after 'while' condition.");
2032 } else if (token == TokenNamedo) {
2034 if (token == TokenNameLISTOPEN) {
2037 throwSyntaxError("'{' expected after 'do' keyword.");
2039 if (token != TokenNameLISTCLOSE) {
2042 if (token == TokenNameLISTCLOSE) {
2045 throwSyntaxError("'}' expected after 'do' keyword.");
2047 if (token == TokenNamewhile) {
2049 if (token == TokenNameARGOPEN) {
2052 throwSyntaxError("'(' expected after 'while' keyword.");
2055 if (token == TokenNameARGCLOSE) {
2058 throwSyntaxError("')' expected after 'while' condition.");
2061 throwSyntaxError("'while' expected after 'do' keyword.");
2063 if (token == TokenNameSEMICOLON) {
2067 throwSyntaxError("';' expected after do-while statement.");
2072 } else if (token == TokenNameforeach) {
2074 if (token == TokenNameARGOPEN) {
2077 throwSyntaxError("'(' expected after 'foreach' keyword.");
2080 if (token == TokenNameas) {
2083 throwSyntaxError("'as' expected after 'foreach' exxpression.");
2086 if (token == TokenNameFOREACH) {
2090 if (token == TokenNameARGCLOSE) {
2093 throwSyntaxError("')' expected after 'foreach' expression.");
2098 } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) {
2100 if (token != TokenNameSEMICOLON) {
2103 if (token == TokenNameSEMICOLON) {
2107 throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
2113 } else if (token == TokenNameecho) {
2116 if (token == TokenNameSEMICOLON) {
2120 throwSyntaxError("';' expected after 'echo' statement.");
2125 // } else if (token == TokenNameprint) {
2128 // if (token == TokenNameSEMICOLON) {
2132 // throwSyntaxError("';' expected after 'print' statement.");
2138 } else if (token == TokenNameglobal || token == TokenNamestatic) {
2141 if (token == TokenNameSEMICOLON) {
2145 throwSyntaxError("';' expected after 'global' or 'static' statement.");
2151 // } else if (token == TokenNameunset) {
2153 // if (token == TokenNameARGOPEN) {
2156 // throwSyntaxError("'(' expected after 'unset' keyword.");
2159 // if (token == TokenNameARGCLOSE) {
2162 // throwSyntaxError("')' expected after 'unset' statement.");
2164 // if (token == TokenNameSEMICOLON) {
2168 // throwSyntaxError("';' expected after 'unset' statement.");
2174 // } else if (token == TokenNameexit || token == TokenNamedie) {
2176 // if (token != TokenNameSEMICOLON) {
2179 // if (token == TokenNameSEMICOLON) {
2183 // throwSyntaxError("';' expected after 'exit' or 'die' statement.");
2189 } else if (token == TokenNamedefine) {
2191 if (token == TokenNameARGOPEN) {
2194 throwSyntaxError("'(' expected after 'define' keyword.");
2197 if (token == TokenNameCOMMA) {
2200 throwSyntaxError("',' expected after first 'define' constant.");
2203 if (token == TokenNameCOMMA) {
2207 if (token == TokenNameARGCLOSE) {
2210 throwSyntaxError("')' expected after 'define' statement.");
2212 if (token == TokenNameSEMICOLON) {
2216 throwSyntaxError("';' expected after 'define' statement.");
2221 } else if (token == TokenNamefunction) {
2223 functionDefinition();
2225 } else if (token == TokenNameclass) {
2231 // throwSyntaxError("Unexpected keyword '" + keyword + "'");
2232 } else if (token == TokenNameLISTOPEN) {
2233 // compoundStatement
2235 if (token != TokenNameLISTCLOSE) {
2238 if (token == TokenNameLISTCLOSE) {
2242 throwSyntaxError("'}' expected.");
2245 if (token != TokenNameSEMICOLON) {
2248 if (token == TokenNameSEMICOLON) {
2253 throwSyntaxError("';' expected after expression.");
2260 private void classDeclarator() throws CoreException {
2262 //identifier 'extends' identifier
2263 if (token == TokenNameIDENTIFIER) {
2265 if (token == TokenNameextends) {
2267 if (token == TokenNameIDENTIFIER) {
2270 throwSyntaxError("Class name expected after keyword 'extends'.");
2274 throwSyntaxError("Class name expected after keyword 'class'.");
2278 private void classBody() throws CoreException {
2279 //'{' [class-element-list] '}'
2280 if (token == TokenNameLISTOPEN) {
2282 if (token != TokenNameLISTCLOSE) {
2285 if (token == TokenNameLISTCLOSE) {
2288 throwSyntaxError("'}' expected at end of class body.");
2291 throwSyntaxError("'{' expected at start of class body.");
2295 private void classElementList() throws CoreException {
2298 } while (token == TokenNamefunction || token == TokenNamevar);
2301 private void classElement() throws CoreException {
2303 //function-definition
2304 if (token == TokenNamefunction) {
2306 functionDefinition();
2307 } else if (token == TokenNamevar) {
2311 throwSyntaxError("'function' or 'var' expected.");
2315 private void classProperty() throws CoreException {
2316 //'var' variable ';'
2317 //'var' variable '=' constant ';'
2319 if (token == TokenNameVARIABLE) {
2321 if (token == TokenNameASSIGN) {
2326 throwSyntaxError("Variable expected after keyword 'var'.");
2328 if (token != TokenNameCOMMA) {
2333 if (token == TokenNameSEMICOLON) {
2336 throwSyntaxError("';' expected after variable declaration.");
2340 private void functionDefinition() throws CoreException {
2341 functionDeclarator();
2342 compoundStatement();
2345 private void functionDeclarator() throws CoreException {
2346 //identifier '(' [parameter-list] ')'
2347 if (token == TokenNameAMPERSAND) {
2350 if (token == TokenNameIDENTIFIER) {
2352 if (token == TokenNameARGOPEN) {
2355 throwSyntaxError("'(' expected in function declaration.");
2357 if (token != TokenNameARGCLOSE) {
2360 if (token != TokenNameARGCLOSE) {
2361 throwSyntaxError("')' expected in function declaration.");
2368 private void parameterList() throws CoreException {
2369 //parameter-declaration
2370 //parameter-list ',' parameter-declaration
2372 parameterDeclaration();
2373 if (token != TokenNameCOMMA) {
2380 private void parameterDeclaration() throws CoreException {
2382 //variable-reference
2383 if (token == TokenNameAMPERSAND) {
2385 if (token == TokenNameVARIABLE) {
2388 throwSyntaxError("Variable expected after reference operator '&'.");
2391 //variable '=' constant
2392 if (token == TokenNameVARIABLE) {
2394 if (token == TokenNameASSIGN) {
2402 private void labeledStatementList() throws CoreException {
2403 if (token != TokenNamecase && token != TokenNamedefault) {
2404 throwSyntaxError("'case' or 'default' expected.");
2407 if (token == TokenNamecase) {
2410 if (token == TokenNameDDOT) {
2412 if (token == TokenNamecase || token == TokenNamedefault) { // empty case statement ?
2416 } else if (token == TokenNameSEMICOLON) {
2417 setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
2419 if (token == TokenNamecase) { // empty case statement ?
2424 throwSyntaxError("':' character after 'case' constant expected.");
2426 } else { // TokenNamedefault
2428 if (token == TokenNameDDOT) {
2432 throwSyntaxError("':' character after 'default' expected.");
2435 } while (token == TokenNamecase || token == TokenNamedefault);
2438 // public void labeledStatement() {
2439 // if (token == TokenNamecase) {
2442 // if (token == TokenNameDDOT) {
2446 // throwSyntaxError("':' character after 'case' constant expected.");
2449 // } else if (token == TokenNamedefault) {
2451 // if (token == TokenNameDDOT) {
2455 // throwSyntaxError("':' character after 'default' expected.");
2461 // public void expressionStatement() {
2464 // private void inclusionStatement() {
2467 // public void compoundStatement() {
2470 // public void selectionStatement() {
2473 // public void iterationStatement() {
2476 // public void jumpStatement() {
2479 // public void outputStatement() {
2482 // public void scopeStatement() {
2485 // public void flowStatement() {
2488 // public void definitionStatement() {
2491 private void ifStatement() throws CoreException {
2492 // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
2493 if (token == TokenNameDDOT) {
2497 case TokenNameelse :
2499 if (token == TokenNameDDOT) {
2503 if (token == TokenNameif) { //'else if'
2505 elseifStatementList();
2507 throwSyntaxError("':' expected after 'else'.");
2511 case TokenNameelseif :
2513 elseifStatementList();
2517 if (token != TokenNameendif) {
2518 throwSyntaxError("'endif' expected.");
2521 if (token != TokenNameSEMICOLON) {
2522 throwSyntaxError("';' expected after if-statement.");
2526 // statement [else-statement]
2528 if (token == TokenNameelseif) {
2530 if (token == TokenNameARGOPEN) {
2533 throwSyntaxError("'(' expected after 'elseif' keyword.");
2536 if (token == TokenNameARGCLOSE) {
2539 throwSyntaxError("')' expected after 'elseif' condition.");
2542 } else if (token == TokenNameelse) {
2549 private void elseifStatementList() throws CoreException {
2553 case TokenNameelse :
2555 if (token == TokenNameDDOT) {
2560 if (token == TokenNameif) { //'else if'
2563 throwSyntaxError("':' expected after 'else'.");
2567 case TokenNameelseif :
2576 private void elseifStatement() throws CoreException {
2577 if (token == TokenNameARGOPEN) {
2580 if (token != TokenNameARGOPEN) {
2581 throwSyntaxError("')' expected in else-if-statement.");
2584 if (token != TokenNameDDOT) {
2585 throwSyntaxError("':' expected in else-if-statement.");
2592 private void switchStatement() throws CoreException {
2593 if (token == TokenNameDDOT) {
2594 // ':' [labeled-statement-list] 'endswitch' ';'
2596 labeledStatementList();
2597 if (token != TokenNameendswitch) {
2598 throwSyntaxError("'endswitch' expected.");
2601 if (token != TokenNameSEMICOLON) {
2602 throwSyntaxError("';' expected after switch-statement.");
2606 // '{' [labeled-statement-list] '}'
2607 if (token != TokenNameLISTOPEN) {
2608 throwSyntaxError("'{' expected in switch statement.");
2611 if (token != TokenNameLISTCLOSE) {
2612 labeledStatementList();
2614 if (token != TokenNameLISTCLOSE) {
2615 throwSyntaxError("'}' expected in switch statement.");
2622 private void forStatement() throws CoreException {
2623 if (token == TokenNameDDOT) {
2626 if (token != TokenNameendfor) {
2627 throwSyntaxError("'endfor' expected.");
2630 if (token != TokenNameSEMICOLON) {
2631 throwSyntaxError("';' expected after for-statement.");
2639 private void whileStatement() throws CoreException {
2640 // ':' statement-list 'endwhile' ';'
2641 if (token == TokenNameDDOT) {
2644 if (token != TokenNameendwhile) {
2645 throwSyntaxError("'endwhile' expected.");
2648 if (token != TokenNameSEMICOLON) {
2649 throwSyntaxError("';' expected after while-statement.");
2657 private void foreachStatement() throws CoreException {
2658 if (token == TokenNameDDOT) {
2661 if (token != TokenNameendforeach) {
2662 throwSyntaxError("'endforeach' expected.");
2665 if (token != TokenNameSEMICOLON) {
2666 throwSyntaxError("';' expected after foreach-statement.");
2674 private void exitStatus() throws CoreException {
2675 if (token == TokenNameARGOPEN) {
2678 throwSyntaxError("'(' expected in 'exit-status'.");
2680 if (token != TokenNameARGCLOSE) {
2683 if (token == TokenNameARGCLOSE) {
2686 throwSyntaxError("')' expected after 'exit-status'.");
2690 private void expressionList() throws CoreException {
2693 if (token == TokenNameCOMMA) {
2701 private void expression() throws CoreException {
2702 //todo: find a better way to get the expression
2703 expression = new StringBuffer();
2704 for (int i = chIndx;i<str.length();i++) {
2705 if (str.charAt(i) == ';') {
2708 expression.append(str.charAt(i));
2710 // if (token == TokenNameSTRING_CONSTANT || token == TokenNameINTERPOLATED_STRING) {
2713 logicalinclusiveorExpression();
2714 // while (token != TokenNameSEMICOLON) {
2720 private void postfixExpression() throws CoreException {
2722 boolean castFlag = false;
2728 case TokenNamenull :
2731 case TokenNamefalse :
2734 case TokenNametrue :
2737 case TokenNameSTRING_CONSTANT :
2740 case TokenNameINTERPOLATED_STRING :
2743 case TokenNameARGOPEN :
2745 if (token == TokenNameIDENTIFIER) {
2746 // check if identifier is a type:
2748 String str = identifier.toLowerCase();
2749 for (int i = 0; i < PHP_TYPES.length; i++) {
2750 if (PHP_TYPES[i].equals(str)) {
2757 if (token != TokenNameARGCLOSE) {
2758 throwSyntaxError(") expected after cast-type '" + ident + "'.");
2768 if (token != TokenNameARGCLOSE) {
2769 throwSyntaxError(") expected in postfix-expression.");
2773 case TokenNameDOUBLE_NUMBER :
2776 case TokenNameINT_NUMBER :
2779 case TokenNameDOLLAROPEN :
2782 if (token != TokenNameLISTCLOSE) {
2783 throwSyntaxError("'}' expected after indirect variable token '${'.");
2787 case TokenNameVARIABLE :
2790 if (token == TokenNameLISTOPEN) {
2793 if (token != TokenNameLISTCLOSE) {
2794 throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression.");
2797 } else if (token == TokenNameARGOPEN) {
2799 if (token != TokenNameARGCLOSE) {
2801 if (token != TokenNameARGCLOSE) {
2802 throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression.");
2808 case TokenNameIDENTIFIER :
2811 if (token == TokenNameARGOPEN) {
2813 if (token != TokenNameARGCLOSE) {
2815 if (token != TokenNameARGCLOSE) {
2816 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
2822 case TokenNameprint :
2825 // if (token == TokenNameSEMICOLON) {
2829 // throwSyntaxError("';' expected after 'print' statement.");
2834 case TokenNamelist :
2836 if (token == TokenNameARGOPEN) {
2838 if (token == TokenNameCOMMA) {
2842 if (token != TokenNameARGCLOSE) {
2843 throwSyntaxError("')' expected after 'list' keyword.");
2846 // if (token == TokenNameSET) {
2848 // logicalinclusiveorExpression();
2851 throwSyntaxError("'(' expected after 'list' keyword.");
2854 // case TokenNameexit :
2856 // if (token != TokenNameSEMICOLON) {
2859 // if (token == TokenNameSEMICOLON) {
2863 // throwSyntaxError("';' expected after 'exit' expression.");
2868 // case TokenNamedie :
2870 // if (token != TokenNameSEMICOLON) {
2873 // if (token == TokenNameSEMICOLON) {
2877 // throwSyntaxError("';' expected after 'die' expression.");
2882 // case TokenNamearray :
2884 // if (token == TokenNameARGOPEN) {
2886 // if (token == TokenNameCOMMA) {
2889 // expressionList();
2890 // if (token != TokenNameARGCLOSE) {
2891 // throwSyntaxError("')' expected after 'list' keyword.");
2894 // if (token == TokenNameSET) {
2896 // logicalinclusiveorExpression();
2899 // throwSyntaxError("'(' expected after 'list' keyword.");
2903 boolean while_flag = true;
2906 case TokenNamePARTOPEN :
2909 if (token != TokenNamePARTCLOSE) {
2910 throwSyntaxError("] expected in postfix-expression.");
2914 case TokenNameDDOT2 : // ::
2915 case TokenNameREF : // ->
2917 if (token > TokenNameKEYWORD) {
2919 setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO);
2922 case TokenNameVARIABLE :
2925 // if (token == TokenNameARGOPEN) {
2927 // expressionList();
2928 // if (token != TokenNameARGCLOSE) {
2929 // throwSyntaxError(") expected after variable '" + ident + "'.");
2934 case TokenNameIDENTIFIER :
2938 case TokenNameLISTOPEN :
2941 if (token != TokenNameLISTCLOSE) {
2942 throwSyntaxError("} expected in postfix-expression.");
2947 throwSyntaxError("Syntax error after '->' token.");
2948 } while (token == TokenNamePARTOPEN || token == TokenNameARGOPEN || token == TokenNameLISTOPEN) {
2949 if (token == TokenNamePARTOPEN) {
2952 if (token != TokenNamePARTCLOSE) {
2953 throwSyntaxError("] expected after '->'.");
2957 if (token == TokenNameARGOPEN) {
2960 if (token != TokenNameARGCLOSE) {
2961 throwSyntaxError(") expected after '->'.");
2965 if (token == TokenNameLISTOPEN) {
2968 if (token != TokenNameLISTCLOSE) {
2969 throwSyntaxError("} expected after '->'.");
2975 case TokenNameINCREMENT :
2978 case TokenNameDECREMENT :
2989 private void unaryExpression() throws CoreException {
2991 case TokenNameINCREMENT :
2995 case TokenNameDECREMENT :
2999 // '@' '&' '*' '+' '-' '~' '!'
3004 case TokenNameAMPERSAND :
3008 case TokenNameMULTIPLY :
3016 case TokenNameSUBTRACT :
3020 case TokenNameTILDE :
3029 postfixExpression();
3033 private void castExpression() throws CoreException {
3034 // if (token == TokenNameARGOPEN) {
3037 // if (token != TokenNameARGCLOSE) {
3038 // throwSyntaxError(") expected after cast-expression.");
3045 private void typeName() throws CoreException {
3046 //'string' 'unset' 'array' 'object'
3048 //'real' 'double' 'float'
3051 if (token == TokenNameIDENTIFIER) {
3053 String str = identifier.toLowerCase();
3055 for (int i = 0; i < PHP_TYPES.length; i++) {
3056 if (PHP_TYPES[i].equals(str)) {
3061 throwSyntaxError("Expected type cast '( <type-name> )'; Got '" + ident + "'.");
3064 private void assignExpression() throws CoreException {
3066 if (token == TokenNameASSIGN) { // =
3068 logicalinclusiveorExpression();
3069 } else if (token == TokenNameDOTASSIGN) { // .=
3071 logicalinclusiveorExpression();
3072 } else if (token == TokenNameFOREACH) { // =>
3074 logicalinclusiveorExpression();
3075 } else if (token == TokenNameADDTO) { // +=
3077 logicalinclusiveorExpression();
3078 } else if (token == TokenNameSUBTRACTFROM) { // -=
3080 logicalinclusiveorExpression();
3081 } else if (token == TokenNameTIMESBY) { // *=
3083 logicalinclusiveorExpression();
3084 } else if (token == TokenNameDIVIDE_EQUAL) { // *=
3086 logicalinclusiveorExpression();
3087 } else if (token == TokenNameREMAINDER_EQUAL) { // %=
3089 logicalinclusiveorExpression();
3090 } else if (token == TokenNameANDASSIGN) { // &=
3092 logicalinclusiveorExpression();
3093 } else if (token == TokenNameXOR_EQUAL) { // ^=
3095 logicalinclusiveorExpression();
3096 } else if (token == TokenNameLEFT_SHIFT_EQUAL) { // <<=
3098 logicalinclusiveorExpression();
3099 } else if (token == TokenNameRIGHT_SHIFT_EQUAL) { // >>=
3101 logicalinclusiveorExpression();
3102 } else if (token == TokenNameTILDEASSIGN) { // ~=
3104 logicalinclusiveorExpression();
3108 private void multiplicativeExpression() throws CoreException {
3111 if (token != TokenNameMULTIPLY && token != TokenNameDIVIDE && token != TokenNameREMAINDER) {
3118 private void concatenationExpression() throws CoreException {
3120 multiplicativeExpression();
3121 if (token != TokenNameDOT) {
3128 private void additiveExpression() throws CoreException {
3130 concatenationExpression();
3131 if (token != TokenNameADD && token != TokenNameSUBTRACT) {
3138 private void shiftExpression() throws CoreException {
3140 additiveExpression();
3141 if (token != TokenNameLEFT_SHIFT && token != TokenNameRIGHT_SHIFT) {
3148 private void relationalExpression() throws CoreException {
3151 if (token != TokenNameLESS && token != TokenNameGREATER && token != TokenNameLESSEQUAL && token != TokenNameGREATEREQUAL) {
3158 private void identicalExpression() throws CoreException {
3160 relationalExpression();
3161 if (token != TokenNameEX_EQUAL && token != TokenNameEX_UNEQUAL) {
3168 private void equalityExpression() throws CoreException {
3170 identicalExpression();
3171 if (token != TokenNameEQUAL && token != TokenNameUNEQUAL) {
3178 private void ternaryExpression() throws CoreException {
3179 equalityExpression();
3180 if (token == TokenNameQUESTIONMARK) {
3183 if (token == TokenNameDDOT) {
3187 throwSyntaxError("':' expected in ternary operator '? :'.");
3192 private void andExpression() throws CoreException {
3194 ternaryExpression();
3195 if (token != TokenNameAMPERSAND) {
3202 private void exclusiveorExpression() throws CoreException {
3205 if (token != TokenNameXOR) {
3212 private void inclusiveorExpression() throws CoreException {
3214 exclusiveorExpression();
3215 if (token != TokenNameLINE) {
3222 private void booleanandExpression() throws CoreException {
3224 inclusiveorExpression();
3225 if (token != TokenNameAND) {
3232 private void booleanorExpression() throws CoreException {
3234 booleanandExpression();
3235 if (token != TokenNameOR) {
3242 private void logicalandExpression() throws CoreException {
3244 booleanorExpression();
3245 if (token != TokenNameand) {
3252 private void logicalexclusiveorExpression() throws CoreException {
3254 logicalandExpression();
3255 if (token != TokenNamexor) {
3262 private void logicalinclusiveorExpression() throws CoreException {
3264 logicalexclusiveorExpression();
3265 if (token != TokenNameor) {
3272 // public void assignmentExpression() {
3273 // if (token == TokenNameVARIABLE) {
3275 // if (token == TokenNameSET) {
3277 // logicalinclusiveorExpression();
3280 // logicalinclusiveorExpression();
3284 private void variableList() throws CoreException {
3287 if (token == TokenNameCOMMA) {
3295 private void variable() throws CoreException {
3296 if (token == TokenNameDOLLAROPEN) {
3300 if (token != TokenNameLISTCLOSE) {
3301 throwSyntaxError("'}' expected after indirect variable token '${'.");
3305 if (token == TokenNameVARIABLE) {
3307 if (token == TokenNamePARTOPEN) {
3310 if (token != TokenNamePARTCLOSE) {
3311 throwSyntaxError("']' expected in variable-list.");
3314 } else if (token == TokenNameASSIGN) {
3319 throwSyntaxError("$-variable expected in variable-list.");
3325 * It will look for a value (after a '=' for example)
3326 * @throws CoreException
3328 private void constant() throws CoreException {
3334 case TokenNameDOUBLE_NUMBER :
3337 case TokenNameINT_NUMBER :
3341 throwSyntaxError("Constant expected after '+' presign.");
3344 case TokenNameSUBTRACT :
3347 case TokenNameDOUBLE_NUMBER :
3350 case TokenNameINT_NUMBER :
3354 throwSyntaxError("Constant expected after '-' presign.");
3357 case TokenNamenull :
3360 case TokenNamefalse :
3363 case TokenNametrue :
3366 case TokenNameIDENTIFIER :
3369 if (token == TokenNameARGOPEN) {
3371 if (token != TokenNameARGCLOSE) {
3373 if (token != TokenNameARGCLOSE) {
3374 throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression.");
3380 case TokenNameSTRING_CONSTANT :
3383 case TokenNameINTERPOLATED_STRING :
3386 case TokenNameDOUBLE_NUMBER :
3389 case TokenNameINT_NUMBER :
3393 throwSyntaxError("Constant expected.");
3398 * Call the php parse command ( php -l -f <filename> )
3399 * and create markers according to the external parser output
3401 public static void phpExternalParse(IFile file) {
3402 //IFile file = (IFile) resource;
3403 IPath path = file.getFullPath();
3404 IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
3405 String filename = file.getLocation().toString();
3407 String[] arguments = { filename };
3408 MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
3409 String command = form.format(arguments);
3411 String parserResult = PHPStartApacheAction.getParserOutput(command, "External parser: ");
3414 // parse the buffer to find the errors and warnings
3415 createMarkers(parserResult, file);
3416 } catch (CoreException e) {
3421 * Create markers according to the external parser output
3423 private static void createMarkers(String output, IFile file) throws CoreException {
3424 // delete all markers
3425 file.deleteMarkers(IMarker.PROBLEM, false, 0);
3429 boolean flag = true;
3430 while ((brIndx = output.indexOf("<br />", indx)) != -1) {
3431 // newer php error output (tested with 4.2.3)
3432 scanLine(output, file, indx, brIndx);
3437 while ((brIndx = output.indexOf("<br>", indx)) != -1) {
3438 // older php error output (tested with 4.2.3)
3439 scanLine(output, file, indx, brIndx);
3445 private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
3447 String outLineNumberString;
3448 StringBuffer lineNumberBuffer = new StringBuffer(10);
3450 current = output.substring(indx, brIndx);
3452 if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
3453 int onLine = current.indexOf("on line <b>");
3455 lineNumberBuffer.delete(0, lineNumberBuffer.length());
3456 for (int i = onLine; i < current.length(); i++) {
3457 ch = current.charAt(i);
3458 if ('0' <= ch && '9' >= ch) {
3459 lineNumberBuffer.append(ch);
3463 int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
3465 Hashtable attributes = new Hashtable();
3467 current = current.replaceAll("\n", "");
3468 current = current.replaceAll("<b>", "");
3469 current = current.replaceAll("</b>", "");
3470 MarkerUtilities.setMessage(attributes, current);
3472 if (current.indexOf(PARSE_ERROR_STRING) != -1)
3473 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
3474 else if (current.indexOf(PARSE_WARNING_STRING) != -1)
3475 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
3477 attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
3478 MarkerUtilities.setLineNumber(attributes, lineNumber);
3479 MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);