options { LOOKAHEAD = 1; CHOICE_AMBIGUITY_CHECK = 2; OTHER_AMBIGUITY_CHECK = 1; STATIC = true; DEBUG_PARSER = false; DEBUG_LOOKAHEAD = false; DEBUG_TOKEN_MANAGER = false; OPTIMIZE_TOKEN_MANAGER = false; ERROR_REPORTING = true; JAVA_UNICODE_ESCAPE = false; UNICODE_INPUT = false; IGNORE_CASE = true; USER_TOKEN_MANAGER = false; USER_CHAR_STREAM = false; BUILD_PARSER = true; BUILD_TOKEN_MANAGER = true; SANITY_CHECK = true; FORCE_LA_CHECK = false; } PARSER_BEGIN(PHPParser) package test; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.runtime.CoreException; import org.eclipse.ui.texteditor.MarkerUtilities; import org.eclipse.jface.preference.IPreferenceStore; import java.util.Hashtable; import java.io.StringReader; import java.text.MessageFormat; import net.sourceforge.phpeclipse.actions.PHPStartApacheAction; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpdt.internal.compiler.parser.PHPOutlineInfo; /** * A new php parser. * This php parser is inspired by the Java 1.2 grammar example * given with JavaCC. You can get JavaCC at http://www.webgain.com * You can test the parser with the PHPParserTestCase2.java * @author Matthieu Casanova */ public class PHPParser extends PHPParserSuperclass { private static PHPParser me; private static IFile fileToParse; 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; public static final int INFO = 0; PHPOutlineInfo outlineInfo; private static int errorLevel = ERROR; private static String errorMessage; public PHPParser() { } public static PHPParser getInstance(IFile fileToParse) { if (me == null) { me = new PHPParser(fileToParse); } else { me.setFileToParse(fileToParse); } return me; } public void setFileToParse(IFile fileToParse) { this.fileToParse = fileToParse; } public static PHPParser getInstance(java.io.Reader stream) { if (me == null) { me = new PHPParser(stream); } else { me.ReInit(stream); } return me; } public PHPParser(IFile fileToParse) { this(new StringReader("")); this.fileToParse = fileToParse; } public void phpParserTester(String strEval) throws CoreException, ParseException { PHPParserTokenManager.SwitchTo(PHPParserTokenManager.PHPPARSING); StringReader stream = new StringReader(strEval); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); } ReInit(new StringReader(strEval)); phpTest(); } public void htmlParserTester(String strEval) throws CoreException, ParseException { StringReader stream = new StringReader(strEval); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); } ReInit(stream); phpFile(); } public PHPOutlineInfo parseInfo(Object parent, String s) { outlineInfo = new PHPOutlineInfo(parent); StringReader stream = new StringReader(s); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); } ReInit(stream); try { parse(); } catch (ParseException e) { if (errorMessage == null) { PHPeclipsePlugin.log(e); } else { setMarker(errorMessage, e.currentToken.beginLine, errorLevel); errorMessage = null; } } return outlineInfo; } /** * Create marker for the parse error */ private static void setMarker(String message, int lineNumber, int errorLevel) { try { setMarker(fileToParse, message, lineNumber, errorLevel); } catch (CoreException e) { PHPeclipsePlugin.log(e); } } public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException { if (file != null) { Hashtable attributes = new Hashtable(); MarkerUtilities.setMessage(attributes, message); switch (errorLevel) { case ERROR : attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR)); break; case WARNING : attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING)); break; case INFO : attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO)); break; } MarkerUtilities.setLineNumber(attributes, lineNumber); MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM); } } /** * 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("
", 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("
", 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; 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 "); 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("", ""); current = current.replaceAll("", ""); 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); } } } public void parse(String s) throws CoreException { ReInit(new StringReader(s)); try { parse(); } catch (ParseException e) { PHPeclipsePlugin.log(e); } } /** * Call the php parse command ( php -l -f <filename> ) * and create markers according to the external parser output */ public static void phpExternalParse(IFile file) { 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.getParserOutput(command, "External parser: "); try { // parse the buffer to find the errors and warnings createMarkers(parserResult, file); } catch (CoreException e) { PHPeclipsePlugin.log(e); } } public void parse() throws ParseException { phpFile(); } } PARSER_END(PHPParser) TOKEN : { : PHPPARSING } TOKEN : { "> : DEFAULT } SKIP : { < ~[] > } /* WHITE SPACE */ SKIP : { " " | "\t" | "\n" | "\r" | "\f" } /* COMMENTS */ MORE : { "//" : IN_SINGLE_LINE_COMMENT | <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT | "/*" : IN_MULTI_LINE_COMMENT } SPECIAL_TOKEN : { " > : PHPPARSING } SPECIAL_TOKEN : { : PHPPARSING } SPECIAL_TOKEN : { : PHPPARSING } MORE : { < ~[] > } /* KEYWORDS */ TOKEN : { | | | | | | } /* LANGUAGE CONSTRUCT */ TOKEN : { | | | | | | | | "> | | "> } /* RESERVED WORDS AND LITERALS */ TOKEN : { < BREAK: "break" > | < CASE: "case" > | < CONST: "const" > | < CONTINUE: "continue" > | < _DEFAULT: "default" > | < DO: "do" > | < EXTENDS: "extends" > | < FALSE: "false" > | < FOR: "for" > | < GOTO: "goto" > | < NEW: "new" > | < NULL: "null" > | < RETURN: "return" > | < SUPER: "super" > | < SWITCH: "switch" > | < THIS: "this" > | < TRUE: "true" > | < WHILE: "while" > | < ENDWHILE : "endwhile" > } /* TYPES */ TOKEN : { | | | | | | | | } TOKEN : { < _ORL : "OR" > | < _ANDL: "AND"> } /* LITERALS */ TOKEN : { < INTEGER_LITERAL: (["l","L"])? | (["l","L"])? | (["l","L"])? > | < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* > | < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ > | < #OCTAL_LITERAL: "0" (["0"-"7"])* > | < FLOATING_POINT_LITERAL: (["0"-"9"])+ "." (["0"-"9"])* ()? (["f","F","d","D"])? | "." (["0"-"9"])+ ()? (["f","F","d","D"])? | (["0"-"9"])+ (["f","F","d","D"])? | (["0"-"9"])+ ()? ["f","F","d","D"] > | < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > | < STRING_LITERAL: ( | | )> | < STRING_1: "\"" ( (~["\""]) | "\\\"" )* "\"" > | < STRING_2: "'" ( (~["'"]))* "'" > | < STRING_3: "`" ( (~["`"]))* "`" > } /* IDENTIFIERS */ TOKEN : { < IDENTIFIER: (|) (||)* > | < #LETTER: ["a"-"z"] | ["A"-"Z"] > | < #DIGIT: ["0"-"9"] > | < #SPECIAL: "_" > } /* SEPARATORS */ TOKEN : { < LPAREN: "(" > | < RPAREN: ")" > | < LBRACE: "{" > | < RBRACE: "}" > | < LBRACKET: "[" > | < RBRACKET: "]" > | < SEMICOLON: ";" > | < COMMA: "," > | < DOT: "." > } /* OPERATORS */ TOKEN : { | | < ASSIGN: "=" > | < GT: ">" > | < LT: "<" > | < BANG: "!" > | < HOOK: "?" > | < COLON: ":" > | < EQ: "==" > | < LE: "<=" > | < GE: ">=" > | < NE: "!=" > | < SC_OR: "||" > | < SC_AND: "&&" > | < INCR: "++" > | < DECR: "--" > | < PLUS: "+" > | < MINUS: "-" > | < STAR: "*" > | < SLASH: "/" > | < BIT_AND: "&" > | < BIT_OR: "|" > | < XOR: "^" > | < REM: "%" > | < LSHIFT: "<<" > | < RSIGNEDSHIFT: ">>" > | < RUNSIGNEDSHIFT: ">>>" > | < PLUSASSIGN: "+=" > | < MINUSASSIGN: "-=" > | < STARASSIGN: "*=" > | < SLASHASSIGN: "/=" > | < ANDASSIGN: "&=" > | < ORASSIGN: "|=" > | < XORASSIGN: "^=" > | < DOTASSIGN: ".=" > | < REMASSIGN: "%=" > | < LSHIFTASSIGN: "<<=" > | < RSIGNEDSHIFTASSIGN: ">>=" > | < RUNSIGNEDSHIFTASSIGN: ">>>=" > } TOKEN : { < DOLLAR_ID: > } /***************************************** * THE JAVA LANGUAGE GRAMMAR STARTS HERE * *****************************************/ /* * Program structuring syntax follows. */ void phpTest() : {} { Php() } void phpFile() : {} { ( Php() )* } void Php() : {} { (BlockStatement())* } void ClassDeclaration() : {} { [ ] ClassBody() } void ClassBody() : {} { ( ClassBodyDeclaration() )* } void ClassBodyDeclaration() : {} { MethodDeclaration() | FieldDeclaration() } void FieldDeclaration() : {} { VariableDeclarator() ( VariableDeclarator() )* } void VariableDeclarator() : {} { VariableDeclaratorId() [ VariableInitializer() ] } void VariableDeclaratorId() : {} { Variable() ( LOOKAHEAD(2) VariableSuffix() )* } void Variable(): {} { ( Expression() ) * | VariableName() } void VariableName(): {} { Expression() | ( Expression() ) * | VariableName() } void VariableInitializer() : {} { Expression() } void ArrayVariable() : {} { Expression() ( Expression())* } void ArrayInitializer() : {} { [ ArrayVariable() ( LOOKAHEAD(2) ArrayVariable() )* ] } void MethodDeclaration() : {} { MethodDeclarator() ( Block() | ) } void MethodDeclarator() : {} { [] FormalParameters() } void FormalParameters() : {} { [ FormalParameter() ( FormalParameter() )* ] } void FormalParameter() : {} { [] VariableDeclarator() } void Type() : {} { | | | | | | | } /* * Expression syntax follows. */ void Expression() : /* * This expansion has been written this way instead of: * Assignment() | ConditionalExpression() * for performance reasons. * However, it is a weakening of the grammar for it allows the LHS of * assignments to be any conditional expression whereas it can only be * a primary expression. Consider adding a semantic predicate to work * around this. */ {} { PrintExpression() | ConditionalExpression() [ AssignmentOperator() Expression() ] } void AssignmentOperator() : {} { | | | | | | | | | | | | } void ConditionalExpression() : {} { ConditionalOrExpression() [ Expression() ConditionalExpression() ] } void ConditionalOrExpression() : {} { ConditionalAndExpression() ( ( | <_ORL>) ConditionalAndExpression() )* } void ConditionalAndExpression() : {} { ConcatExpression() ( ( | <_ANDL>) ConcatExpression() )* } void ConcatExpression() : {} { InclusiveOrExpression() ( InclusiveOrExpression() )* } void InclusiveOrExpression() : {} { ExclusiveOrExpression() ( ExclusiveOrExpression() )* } void ExclusiveOrExpression() : {} { AndExpression() ( AndExpression() )* } void AndExpression() : {} { EqualityExpression() ( EqualityExpression() )* } void EqualityExpression() : {} { RelationalExpression() ( ( | ) RelationalExpression() )* } void RelationalExpression() : {} { ShiftExpression() ( ( | | | ) ShiftExpression() )* } void ShiftExpression() : {} { AdditiveExpression() ( ( | | ) AdditiveExpression() )* } void AdditiveExpression() : {} { MultiplicativeExpression() ( ( | ) MultiplicativeExpression() )* } void MultiplicativeExpression() : {} { UnaryExpression() ( ( | | ) UnaryExpression() )* } void UnaryExpression() : {} { UnaryExpression() | ( | ) UnaryExpression() | PreIncrementExpression() | PreDecrementExpression() | UnaryExpressionNotPlusMinus() } void PreIncrementExpression() : {} { PrimaryExpression() } void PreDecrementExpression() : {} { PrimaryExpression() } void UnaryExpressionNotPlusMinus() : {} { UnaryExpression() | LOOKAHEAD( Type() ) CastExpression() | PostfixExpression() | Literal() | Expression() } void CastExpression() : {} { Type() UnaryExpression() } void PostfixExpression() : {} { PrimaryExpression() [ | ] } void PrimaryExpression() : {} { LOOKAHEAD(2) ClassIdentifier() (PrimarySuffix())* | PrimaryPrefix() ( PrimarySuffix() )* | ArrayInitializer() } void PrimaryPrefix() : {} { | ClassIdentifier() | VariableDeclaratorId() } void ClassIdentifier(): {} { | VariableDeclaratorId() } void PrimarySuffix() : {} { Arguments() | VariableSuffix() } void VariableSuffix() : {} { VariableName() | [ Expression() ] } void Literal() : {} { | | | BooleanLiteral() | NullLiteral() } void BooleanLiteral() : {} { | } void NullLiteral() : {} { } void Arguments() : {} { [ ArgumentList() ] } void ArgumentList() : {} { Expression() ( Expression() )* } /* * Statement syntax follows. */ void Statement() : {} { LOOKAHEAD(2) Expression() ( | "?>") | LOOKAHEAD(2) LabeledStatement() | Block() | EmptyStatement() | StatementExpression() try { } catch (ParseException e) { errorMessage = "';' expected after expression"; errorLevel = ERROR; throw e; } | SwitchStatement() | IfStatement() | WhileStatement() | DoStatement() | ForStatement() | BreakStatement() | ContinueStatement() | ReturnStatement() | EchoStatement() | IncludeStatement() | StaticStatement() | GlobalStatement() } void IncludeStatement() : {} { Expression() ( | "?>") | Expression() ( | "?>") | Expression() ( | "?>") | Expression() ( | "?>") } void PrintExpression() : {} { Expression() } void EchoStatement() : {} { Expression() ( Expression())* try { ( | "?>") } catch (ParseException e) { errorMessage = "';' expected after 'echo' statement"; errorLevel = ERROR; throw e; } } void GlobalStatement() : {} { VariableDeclaratorId() ( VariableDeclaratorId())* ( | "?>") } void StaticStatement() : {} { VariableDeclarator() ( VariableDeclarator())* ( | "?>") } void LabeledStatement() : {} { Statement() } void Block() : {} { ( BlockStatement() )* } void BlockStatement() : {} { Statement() | ClassDeclaration() | MethodDeclaration() } void LocalVariableDeclaration() : {} { VariableDeclarator() ( VariableDeclarator() )* } void EmptyStatement() : {} { } void StatementExpression() : /* * The last expansion of this production accepts more than the legal * Java expansions for StatementExpression. This expansion does not * use PostfixExpression for performance reasons. */ {} { PreIncrementExpression() | PreDecrementExpression() | PrimaryExpression() [ | | AssignmentOperator() Expression() ] } void SwitchStatement() : {} { Expression() ( SwitchLabel() ( BlockStatement() )* )* } void SwitchLabel() : {} { Expression() | <_DEFAULT> } void IfStatement() : /* * The disambiguating algorithm of JavaCC automatically binds dangling * else's to the innermost if statement. The LOOKAHEAD specification * is to tell JavaCC that we know what we are doing. */ {} { Condition("if") Statement() [ LOOKAHEAD(1) ElseIfStatement() ] [ LOOKAHEAD(1) Statement() ] } void Condition(String keyword) : {} { try { } catch (ParseException e) { errorMessage = "'(' expected after " + keyword + " keyword"; errorLevel = ERROR; throw e; } Expression() try { } catch (ParseException e) { errorMessage = "')' expected after " + keyword + " keyword"; errorLevel = ERROR; throw e; } } void ElseIfStatement() : {} { Condition("elseif") Statement() } void WhileStatement() : {} { Condition("while") WhileStatement0() } void WhileStatement0() : {} { (Statement())* ( | "?>") | Statement() } void DoStatement() : {} { Statement() Condition("while") ( | "?>") } void ForStatement() : {} { [ ForInit() ] [ Expression() ] [ ForUpdate() ] Statement() } void ForInit() : {} { LOOKAHEAD(LocalVariableDeclaration()) LocalVariableDeclaration() | StatementExpressionList() } void StatementExpressionList() : {} { StatementExpression() ( StatementExpression() )* } void ForUpdate() : {} { StatementExpressionList() } void BreakStatement() : {} { [ ] } void ContinueStatement() : {} { [ ] } void ReturnStatement() : {} { [ Expression() ] }