**********************************************************************/
package net.sourceforge.phpeclipse.phpeditor;
+import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
+import net.sourceforge.phpeclipse.PHPeclipsePlugin;
+import net.sourceforge.phpeclipse.actions.PHPStartApacheAction;
import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.texteditor.MarkerUtilities;
public class PHPParser extends PHPKeywords {
+ // strings for external parser call
+ private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$
+ private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$
public static final int ERROR = 2;
public static final int WARNING = 1;
final static int TT_QUESTIONMARK = 61;
final static int TT_DDOT2 = 62;
final static int TT_AT = 63;
+ // final static int TT_HEREDOC = 64;
final static int TT_DOLLAROPEN = 127;
final static int TT_ARGOPEN = 128;
throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error);
}
+ private void throwSyntaxError(String error, int startRow) {
+
+ throw new SyntaxError(startRow, 0, " ", error);
+ }
+
/**
* Method Declaration.
*
} else if (ch == '\'') {
// read string until end
boolean openString = true;
+ int startRow = rowCount;
while (str.length() > chIndx) {
ch = str.charAt(chIndx++);
if (ch == '\\') {
}
}
if (openString) {
- throwSyntaxError("Open string character \"'\" at end of file.");
+ throwSyntaxError("Open string character \"'\" at end of file.", startRow);
}
token = TT_STRING_CONSTANT;
return;
} else if (ch == '`') {
// read string until end
boolean openString = true;
+ int startRow = rowCount;
while (str.length() > chIndx) {
ch = str.charAt(chIndx++);
if (ch == '\\') {
}
}
if (openString) {
- throwSyntaxError("Open string character \"`\" at end of file.");
+ throwSyntaxError("Open string character \"`\" at end of file.", startRow);
}
setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO);
token = TT_STRING_CONSTANT;
if (str.charAt(chIndx) == '<') {
chIndx++;
token = TT_LSHIFT;
- if (str.length() > chIndx) {
- if (str.charAt(chIndx) == '=') {
- chIndx++;
- token = TT_LSHIFTASSIGN;
- break;
+ if (str.charAt(chIndx) == '<') {
+ // heredoc
+ int startRow = rowCount;
+ if (str.length() > chIndx) {
+
+ ch = str.charAt(++chIndx);
+ if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) {
+ chIndx++;
+ getIdentifier();
+ token = TT_STRING_CONSTANT;
+ while (str.length() > chIndx) {
+ ch = str.charAt(chIndx++);
+ if (ch == '\n') {
+ if (str.length() >= chIndx + identifier.length()) {
+ if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) {
+ chIndx += identifier.length();
+ return;
+ }
+ }
+ }
+ }
+ }
}
+ throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow);
+ } else if (str.charAt(chIndx) == '=') {
+ chIndx++;
+ token = TT_LSHIFTASSIGN;
+ break;
}
break;
}
}
public void phpParse(String s, int rowCount) throws CoreException {
- // start up
- try {
- this.str = s;
- if (s == null) {
- if (phpList.size() != 0) {
- this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
- }
+ this.str = s;
+ if (s == null) {
+ if (phpList.size() != 0) {
+ this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
}
- this.token = TT_EOF;
- this.chIndx = 0;
- this.rowCount = rowCount;
- this.columnCount = 0;
- this.phpEnd = false;
- getNextToken();
- if (token != TT_EOF && token != TT_UNDEFINED) {
- statementList();
- }
- if (token != TT_EOF && token != TT_UNDEFINED) {
- if (token == TT_ARGCLOSE) {
- throwSyntaxError("too many closing ')'; end-of-file not reached");
- }
- if (token == TT_LISTCLOSE) {
- throwSyntaxError("too many closing '}'; end-of-file not reached");
- }
- if (token == TT_PARTCLOSE) {
- throwSyntaxError("too many closing ']'; end-of-file not reached");
+ }
+ this.token = TT_EOF;
+ this.chIndx = 0;
+ this.rowCount = rowCount;
+ this.columnCount = 0;
+ this.phpEnd = false;
+ getNextToken();
+ do {
+ try {
+ if (token != TT_EOF && token != TT_UNDEFINED) {
+ statementList();
}
+ if (token != TT_EOF && token != TT_UNDEFINED) {
+ if (token == TT_ARGCLOSE) {
+ throwSyntaxError("Too many closing ')'; end-of-file not reached.");
+ }
+ if (token == TT_LISTCLOSE) {
+ throwSyntaxError("Too many closing '}'; end-of-file not reached.");
+ }
+ if (token == TT_PARTCLOSE) {
+ throwSyntaxError("Too many closing ']'; end-of-file not reached.");
+ }
- if (token == TT_ARGOPEN) {
- throwSyntaxError("read character '('; end-of-file not reached");
+ if (token == TT_ARGOPEN) {
+ throwSyntaxError("Read character '('; end-of-file not reached.");
+ }
+ if (token == TT_LISTOPEN) {
+ throwSyntaxError("Read character '{'; end-of-file not reached.");
+ }
+ if (token == TT_PARTOPEN) {
+ throwSyntaxError("Read character '['; end-of-file not reached.");
+ }
+
+ throwSyntaxError("End-of-file not reached.");
}
- if (token == TT_LISTOPEN) {
- throwSyntaxError("read character '{'; end-of-file not reached");
+ return;
+ } catch (SyntaxError err) {
+ if (s != null) {
+ throw err;
+ } else {
+ setMarker(err.getMessage(), err.getLine(), ERROR);
}
- if (token == TT_PARTOPEN) {
- throwSyntaxError("read character '['; end-of-file not reached");
+ // if an error occured,
+ // try to find keywords 'class' or 'function'
+ // to parse the rest of the string
+ while (token != TT_EOF && token != TT_UNDEFINED) {
+ if (token == TT_class || token == TT_function) {
+ break;
+ }
+ getNextToken();
+ }
+ if (token == TT_EOF || token == TT_UNDEFINED) {
+ return;
}
-
- throwSyntaxError("end-of-file not reached");
- }
- } catch (SyntaxError err) {
- if (s != null) {
- throw err;
- } else {
- setMarker(err.getMessage(), err.getLine(), ERROR);
}
}
+ while (true);
}
private void statementList() throws CoreException {
}
}
return;
- } else if (token == TT_print) {
- getNextToken();
- expression();
- if (token == TT_SEMICOLON) {
- getNextToken();
- } else {
- if (!phpEnd) {
- throwSyntaxError("';' expected after 'print' statement.");
- }
- }
- return;
+ // } else if (token == TT_print) {
+ // getNextToken();
+ // expression();
+ // if (token == TT_SEMICOLON) {
+ // getNextToken();
+ // } else {
+ // if (!phpEnd) {
+ // throwSyntaxError("';' expected after 'print' statement.");
+ // }
+ // }
+ // return;
} else if (token == TT_global || token == TT_static) {
getNextToken();
getNextToken();
}
break;
+ case TT_print :
+ getNextToken();
+ expression();
+ // if (token == TT_SEMICOLON) {
+ // getNextToken();
+ // } else {
+ // if (!phpEnd) {
+ // throwSyntaxError("';' expected after 'print' statement.");
+ // }
+ // }
+ break;
case TT_list :
getNextToken();
if (token == TT_ARGOPEN) {
}
}
+ /**
+ * Call the php parse command ( php -l -f <filename> )
+ * and create markers according to the external parser output
+ */
+ public static void phpExternalParse(IFile file) {
+ //IFile file = (IFile) resource;
+ IPath path = file.getFullPath();
+ IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+ String filename = file.getLocation().toString();
+
+ String[] arguments = { filename };
+ MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF));
+ String command = form.format(arguments);
+
+ String parserResult = PHPStartApacheAction.execute(command, "External parser: ");
+
+ try {
+ // parse the buffer to find the errors and warnings
+ createMarkers(parserResult, file);
+ } catch (CoreException e) {
+ }
+ }
+
+ /**
+ * Create markers according to the external parser output
+ */
+ private static void createMarkers(String output, IFile file) throws CoreException {
+ // delete all markers
+ file.deleteMarkers(IMarker.PROBLEM, false, 0);
+
+ int indx = 0;
+ int brIndx = 0;
+ boolean flag = true;
+ while ((brIndx = output.indexOf("<br />", indx)) != -1) {
+ // newer php error output (tested with 4.2.3)
+ scanLine(output, file, indx, brIndx);
+ indx = brIndx + 6;
+ flag = false;
+ }
+ if (flag) {
+ while ((brIndx = output.indexOf("<br>", indx)) != -1) {
+ // older php error output (tested with 4.2.3)
+ scanLine(output, file, indx, brIndx);
+ indx = brIndx + 4;
+ }
+ }
+ }
+
+ private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException {
+ String current;
+ String outLineNumberString;
+ StringBuffer lineNumberBuffer = new StringBuffer(10);
+ char ch;
+ current = output.substring(indx, brIndx);
+
+ if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) {
+ int onLine = current.indexOf("on line <b>");
+ if (onLine != -1) {
+ lineNumberBuffer.delete(0, lineNumberBuffer.length());
+ for (int i = onLine; i < current.length(); i++) {
+ ch = current.charAt(i);
+ if ('0' <= ch && '9' >= ch) {
+ lineNumberBuffer.append(ch);
+ }
+ }
+
+ int lineNumber = Integer.parseInt(lineNumberBuffer.toString());
+
+ Hashtable attributes = new Hashtable();
+
+ current = current.replaceAll("\n", "");
+ current = current.replaceAll("<b>", "");
+ current = current.replaceAll("</b>", "");
+ MarkerUtilities.setMessage(attributes, current);
+
+ if (current.indexOf(PARSE_ERROR_STRING) != -1)
+ attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
+ else if (current.indexOf(PARSE_WARNING_STRING) != -1)
+ attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
+ else
+ attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
+ MarkerUtilities.setLineNumber(attributes, lineNumber);
+ MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
+ }
+ }
+ }
}
\ No newline at end of file