options { LOOKAHEAD = 1; CHOICE_AMBIGUITY_CHECK = 2; OTHER_AMBIGUITY_CHECK = 1; STATIC = false; 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; COMMON_TOKEN_ACTION = true; } 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.util.ArrayList; import java.io.StringReader; import java.io.*; import java.text.MessageFormat; import net.sourceforge.phpeclipse.actions.PHPStartApacheAction; import net.sourceforge.phpeclipse.PHPeclipsePlugin; import net.sourceforge.phpdt.internal.compiler.ast.*; import net.sourceforge.phpdt.internal.compiler.parser.OutlineableWithChildren; import net.sourceforge.phpdt.internal.compiler.parser.Outlineable; import net.sourceforge.phpdt.internal.compiler.parser.PHPOutlineInfo; import net.sourceforge.phpdt.internal.corext.Assert; /** * 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 final class PHPParser extends PHPParserSuperclass { //todo : fix the variables names bug //todo : handle tilde operator /** The current segment. */ private static OutlineableWithChildren currentSegment; private static final String PARSE_ERROR_STRING = "Parse error"; //$NON-NLS-1$ private static final String PARSE_WARNING_STRING = "Warning"; //$NON-NLS-1$ static PHPOutlineInfo outlineInfo; /** The error level of the current ParseException. */ private static int errorLevel = ERROR; /** The message of the current ParseException. If it's null it's because the parse exception wasn't handled */ private static String errorMessage; private static int errorStart = -1; private static int errorEnd = -1; private static PHPDocument phpDocument; private static final String SYNTAX_ERROR_CHAR = "syntax error"; /** * The point where html starts. * It will be used by the token manager to create HTMLCode objects */ public static int htmlStart; //ast stack private final static int AstStackIncrement = 100; /** The stack of node. */ private static AstNode[] nodes; /** The cursor in expression stack. */ private static int nodePtr; public static final boolean PARSER_DEBUG = false; public final void setFileToParse(final IFile fileToParse) { PHPParser.fileToParse = fileToParse; } public PHPParser() { } public PHPParser(final IFile fileToParse) { this(new StringReader("")); PHPParser.fileToParse = fileToParse; } public final void phpParserTester(final String strEval) throws ParseException { final StringReader stream = new StringReader(strEval); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new PHPParserTokenManager(jj_input_stream); } ReInit(new StringReader(strEval)); init(); phpDocument = new PHPDocument(null,"_root".toCharArray()); currentSegment = phpDocument; outlineInfo = new PHPOutlineInfo(null, currentSegment); token_source.SwitchTo(PHPParserTokenManager.PHPPARSING); phpTest(); } public final void htmlParserTester(final File fileName) throws FileNotFoundException, ParseException { final Reader stream = new FileReader(fileName); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new PHPParserTokenManager(jj_input_stream); } ReInit(stream); init(); phpDocument = new PHPDocument(null,"_root".toCharArray()); currentSegment = phpDocument; outlineInfo = new PHPOutlineInfo(null, currentSegment); phpFile(); } public final void htmlParserTester(final String strEval) throws ParseException { final StringReader stream = new StringReader(strEval); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new PHPParserTokenManager(jj_input_stream); } ReInit(stream); init(); phpDocument = new PHPDocument(null,"_root".toCharArray()); currentSegment = phpDocument; outlineInfo = new PHPOutlineInfo(null, currentSegment); phpFile(); } /** * Reinitialize the parser. */ private static final void init() { nodes = new AstNode[AstStackIncrement]; nodePtr = -1; htmlStart = 0; } /** * Add an php node on the stack. * @param node the node that will be added to the stack */ private static final void pushOnAstNodes(final AstNode node) { try { nodes[++nodePtr] = node; } catch (IndexOutOfBoundsException e) { final int oldStackLength = nodes.length; final AstNode[] oldStack = nodes; nodes = new AstNode[oldStackLength + AstStackIncrement]; System.arraycopy(oldStack, 0, nodes, 0, oldStackLength); nodePtr = oldStackLength; nodes[nodePtr] = node; } } public final PHPOutlineInfo parseInfo(final Object parent, final String s) { phpDocument = new PHPDocument(parent,"_root".toCharArray()); currentSegment = phpDocument; outlineInfo = new PHPOutlineInfo(parent, currentSegment); final StringReader stream = new StringReader(s); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new PHPParserTokenManager(jj_input_stream); } ReInit(stream); init(); try { parse(); phpDocument.nodes = new AstNode[nodes.length]; System.arraycopy(nodes,0,phpDocument.nodes,0,nodes.length); if (PHPeclipsePlugin.DEBUG) { PHPeclipsePlugin.log(1,phpDocument.toString()); } } catch (ParseException e) { processParseException(e); } return outlineInfo; } /** * This function will throw the exception if we are in debug mode * and process it if we are in production mode. * this should be fast since the PARSER_DEBUG is static final so the difference will be at compile time * @param e the exception * @throws ParseException the thrown exception */ private static void processParseExceptionDebug(final ParseException e) throws ParseException { if (PARSER_DEBUG) { throw e; } processParseException(e); } /** * This method will process the parse exception. * If the error message is null, the parse exception wasn't catched and a trace is written in the log * @param e the ParseException */ private static void processParseException(final ParseException e) { if (errorMessage == null) { PHPeclipsePlugin.log(e); errorMessage = "this exception wasn't handled by the parser please tell us how to reproduce it"; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; } setMarker(e); errorMessage = null; // if (PHPeclipsePlugin.DEBUG) PHPeclipsePlugin.log(e); } /** * Create marker for the parse error. * @param e the ParseException */ private static void setMarker(final ParseException e) { try { if (errorStart == -1) { setMarker(fileToParse, errorMessage, e.currentToken.sourceStart, e.currentToken.sourceEnd, errorLevel, "Line " + e.currentToken.beginLine+", "+e.currentToken.sourceStart+':'+e.currentToken.sourceEnd); } else { setMarker(fileToParse, errorMessage, errorStart, errorEnd, errorLevel, "Line " + e.currentToken.beginLine+", "+errorStart+':'+errorEnd); errorStart = -1; errorEnd = -1; } } catch (CoreException e2) { PHPeclipsePlugin.log(e2); } } private static void scanLine(final String output, final IFile file, final int indx, final int brIndx) throws CoreException { String current; final 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) { final 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); } } final int lineNumber = Integer.parseInt(lineNumberBuffer.toString()); final 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 final void parse(final String s) { final StringReader stream = new StringReader(s); if (jj_input_stream == null) { jj_input_stream = new SimpleCharStream(stream, 1, 1); token_source = new PHPParserTokenManager(jj_input_stream); } ReInit(stream); init(); try { parse(); } catch (ParseException e) { processParseException(e); } } /** * Call the php parse command ( php -l -f <filename> ) * and create markers according to the external parser output */ public static void phpExternalParse(final IFile file) { final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore(); final String filename = file.getLocation().toString(); final String[] arguments = { filename }; final MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF)); final String command = form.format(arguments); final 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); } } /** * Put a new html block in the stack. */ public final void createNewHTMLCode() { final int currentPosition = token.sourceStart; if (currentPosition == htmlStart || currentPosition < htmlStart || currentPosition > jj_input_stream.getCurrentBuffer().length()) { return; } final String html = jj_input_stream.getCurrentBuffer().substring(htmlStart, currentPosition); pushOnAstNodes(new HTMLCode(html, htmlStart,currentPosition)); } /** Create a new task. */ public final void createNewTask(final int todoStart) { final String todo = jj_input_stream.getCurrentBuffer().substring(todoStart, jj_input_stream.getCurrentBuffer().indexOf("\n", todoStart)-1); if (!PARSER_DEBUG) { try { setMarker(fileToParse, todo, jj_input_stream.getBeginLine(), TASK, "Line "+jj_input_stream.getBeginLine()); } catch (CoreException e) { PHPeclipsePlugin.log(e); } } } private final void parse() throws ParseException { phpFile(); } } PARSER_END(PHPParser) TOKEN_MGR_DECLS: { // CommonTokenAction: use the begins/ends fields added to the Jack // CharStream class to set corresponding fields in each Token (which was // also extended with new fields). By default Jack doesn't supply absolute // offsets, just line/column offsets void CommonTokenAction(Token t) { t.sourceStart = input_stream.getBeginOffset(); t.sourceEnd = input_stream.getBeginOffset(); } // CommonTokenAction } // TOKEN_MGR_DECLS TOKEN : { : PHPPARSING | : PHPPARSING | "> : DEFAULT } /* Skip any character if we are not in php mode */ SKIP : { < ~[] > } /* WHITE SPACE */ SKIP : { " " | "\t" | "\n" | "\r" | "\f" } SPECIAL_TOKEN : { " " : PHPPARSING | "\t" : PHPPARSING | "\n" : PHPPARSING | "\r" : PHPPARSING | "\f" : PHPPARSING } /* COMMENTS */ SPECIAL_TOKEN : { "//" : IN_SINGLE_LINE_COMMENT | "#" : IN_SINGLE_LINE_COMMENT | <"/**" ~["/"]> { input_stream.backup(1); } : IN_FORMAL_COMMENT | "/*" : IN_MULTI_LINE_COMMENT } SPECIAL_TOKEN : { : PHPPARSING | < ~[] > } SPECIAL_TOKEN : { "todo" } void todo() : {Token todoToken;} { todoToken = "TODO" {createNewTask(todoToken.sourceStart);} } SPECIAL_TOKEN : { "*/" : PHPPARSING } SPECIAL_TOKEN : { "*/" : PHPPARSING } MORE : { < ~[] > } /* KEYWORDS */ TOKEN : { | | | | | | | | } /* LANGUAGE CONSTRUCT */ TOKEN : { | | | | | | | | } TOKEN : { "> : PHPPARSING | : PHPPARSING | "> : PHPPARSING } /* RESERVED WORDS AND LITERALS */ TOKEN : { | | | <_DEFAULT : "default"> | | | | | | | | | | | | | | | | | | | } /* TYPES */ TOKEN : { | | | | | | | | } //Misc token TOKEN : { : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING } /* OPERATORS */ TOKEN : { : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | >"> : PHPPARSING | >>"> : PHPPARSING | <_ORL : "OR"> : PHPPARSING | <_ANDL : "AND"> : PHPPARSING } /* LITERALS */ TOKEN : { (["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"])* > | )? (["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"])+ > | | )> //| | | } SKIP : { : IN_STRING } TOKEN : { : IN_STRING } TOKEN : { : DOLLAR_IN_STRING } TOKEN : { : PHPPARSING } TOKEN : { : DOLLAR_IN_STRING_EXPR } SPECIAL_TOKEN : { <"{"> : SKIPSTRING } SPECIAL_TOKEN : { <"}"> : IN_STRING } SKIP : { <~[]> } TOKEN : { : DOLLAR_IN_STRING } TOKEN : { } SKIP : { <~[]> } SKIP : { <~[]> } /* IDENTIFIERS */ TOKEN : { : IN_VARIABLE} TOKEN : { |) (||)* > | < #LETTER: ["a"-"z"] | ["A"-"Z"] > | < #DIGIT: ["0"-"9"] > | < #SPECIAL: "_" | ["\u007f"-"\u00ff"] > } SPECIAL_TOKEN : { < ~[] > : IN_STRING } /* SEPARATORS */ TOKEN : { : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING | : PHPPARSING } /* COMPARATOR */ TOKEN : { "> : PHPPARSING | : PHPPARSING | : PHPPARSING | ="> : PHPPARSING | "> : PHPPARSING | : PHPPARSING | : PHPPARSING } /* ASSIGNATION */ TOKEN : { : PHPPARSING | >="> : PHPPARSING } void phpTest() : {} { Php() } void phpFile() : {} { try { (PhpBlock())* {createNewHTMLCode();} } catch (TokenMgrError e) { PHPeclipsePlugin.log(e); errorStart = jj_input_stream.getBeginOffset(); errorEnd = jj_input_stream.getEndOffset(); errorMessage = e.getMessage(); errorLevel = ERROR; throw generateParseException(); } } /** * A php block is a * or * or */ void PhpBlock() : { final PHPEchoBlock phpEchoBlock; final Token token,phpEnd; } { phpEchoBlock = phpEchoBlock() {pushOnAstNodes(phpEchoBlock);} | [ | token = {try { setMarker(fileToParse, "You should use ' {htmlStart = phpEnd.sourceEnd;} } catch (ParseException e) { errorMessage = "'?>' expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } } PHPEchoBlock phpEchoBlock() : { final Expression expr; final PHPEchoBlock echoBlock; final Token token, token2; } { token = {createNewHTMLCode();} expr = Expression() [ ] token2 = { htmlStart = token2.sourceEnd; echoBlock = new PHPEchoBlock(expr,token.sourceStart,token2.sourceEnd); pushOnAstNodes(echoBlock); return echoBlock;} } void Php() : {} { (BlockStatement())* } ClassDeclaration ClassDeclaration() : { final ClassDeclaration classDeclaration; Token className = null; final Token superclassName, token, extendsToken; String classNameImage = SYNTAX_ERROR_CHAR; String superclassNameImage = null; final int classEnd; } { token = try { className = {classNameImage = className.image;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected"; errorLevel = ERROR; errorStart = token.sourceEnd+1; errorEnd = token.sourceEnd+1; processParseExceptionDebug(e); } [ extendsToken = try { superclassName = {superclassNameImage = superclassName.image;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', identifier expected"; errorLevel = ERROR; errorStart = extendsToken.sourceEnd+1; errorEnd = extendsToken.sourceEnd+1; processParseExceptionDebug(e); superclassNameImage = SYNTAX_ERROR_CHAR; } ] { int start, end; if (className == null) { start = token.sourceStart; end = token.sourceEnd; } else { start = className.sourceStart; end = className.sourceEnd; } if (superclassNameImage == null) { classDeclaration = new ClassDeclaration(currentSegment, classNameImage, start, end); } else { classDeclaration = new ClassDeclaration(currentSegment, classNameImage, superclassNameImage, start, end); } currentSegment.add(classDeclaration); currentSegment = classDeclaration; } classEnd = ClassBody(classDeclaration) {currentSegment = (OutlineableWithChildren) currentSegment.getParent(); classDeclaration.sourceEnd = classEnd; pushOnAstNodes(classDeclaration); return classDeclaration;} } int ClassBody(final ClassDeclaration classDeclaration) : { Token token; } { try { } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image + "'. '{' expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } ( ClassBodyDeclaration(classDeclaration) )* try { token = {return token.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. 'var', 'function' or '}' expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); return this.token.sourceEnd; } } /** * A class can contain only methods and fields. */ void ClassBodyDeclaration(final ClassDeclaration classDeclaration) : { final MethodDeclaration method; final FieldDeclaration field; } { method = MethodDeclaration() {method.analyzeCode(); classDeclaration.addMethod(method);} | field = FieldDeclaration() {classDeclaration.addField(field);} } /** * A class field declaration : it's var VariableDeclarator() (, VariableDeclarator())*;. * it is only used by ClassBodyDeclaration() */ FieldDeclaration FieldDeclaration() : { VariableDeclaration variableDeclaration; final VariableDeclaration[] list; final ArrayList arrayList = new ArrayList(); final Token token; Token token2 = null; int pos; } { token = variableDeclaration = VariableDeclaratorNoSuffix() { arrayList.add(variableDeclaration); pos = variableDeclaration.sourceEnd; } ( variableDeclaration = VariableDeclaratorNoSuffix() { arrayList.add(variableDeclaration); outlineInfo.addVariable(variableDeclaration.name()); pos = variableDeclaration.sourceEnd; } )* try { token2 = } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected after variable declaration"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseExceptionDebug(e); } {list = new VariableDeclaration[arrayList.size()]; arrayList.toArray(list); int end; if (token2 == null) { end = list[list.length-1].sourceEnd; } else { end = token2.sourceEnd; } return new FieldDeclaration(list, token.sourceStart, end, currentSegment);} } /** * a strict variable declarator : there cannot be a suffix here. * It will be used by fields and formal parameters */ VariableDeclaration VariableDeclaratorNoSuffix() : { final Token token, lbrace,rbrace; Expression expr, initializer = null; Token assignToken; Variable variable; } { ( token = {variable = new Variable(token.image,token.sourceStart,token.sourceEnd);} | lbrace = expr = Expression() rbrace = {variable = new Variable(expr,lbrace.sourceStart,rbrace.sourceEnd);} ) [ assignToken = try { initializer = VariableInitializer() } catch (ParseException e) { errorMessage = "Literal expression expected in variable initializer"; errorLevel = ERROR; errorStart = assignToken.sourceEnd +1; errorEnd = assignToken.sourceEnd +1; processParseExceptionDebug(e); } ] { if (initializer == null) { return new VariableDeclaration(currentSegment, variable, variable.sourceStart, variable.sourceEnd); } return new VariableDeclaration(currentSegment, variable, initializer, VariableDeclaration.EQUAL, variable.sourceStart); } } /** * this will be used by static statement */ VariableDeclaration VariableDeclarator() : { final AbstractVariable variable; Expression initializer = null; final Token token; } { variable = VariableDeclaratorId() [ token = try { initializer = VariableInitializer() } catch (ParseException e) { errorMessage = "Literal expression expected in variable initializer"; errorLevel = ERROR; errorStart = token.sourceEnd+1; errorEnd = token.sourceEnd+1; processParseExceptionDebug(e); } ] { if (initializer == null) { return new VariableDeclaration(currentSegment, variable, variable.sourceStart, variable.sourceEnd); } return new VariableDeclaration(currentSegment, variable, initializer, VariableDeclaration.EQUAL, variable.sourceStart); } } /** * A Variable name. * @return the variable name (with suffix) */ AbstractVariable VariableDeclaratorId() : { AbstractVariable var; } { try { var = Variable() ( LOOKAHEAD(2) var = VariableSuffix(var) )* { return var; } } catch (ParseException e) { errorMessage = "'$' expected for variable identifier"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } } Variable Variable() : { Variable variable = null; final Token token; } { token = variable = Var() { return variable; } } Variable Var() : { Variable variable = null; final Token token,token2; ConstantIdentifier constant; Expression expression; } { token = variable = Var() {return new Variable(variable,variable.sourceStart,variable.sourceEnd);} | token = expression = Expression() token2 = { return new Variable(expression, token.sourceStart, token2.sourceEnd); } | token = { outlineInfo.addVariable('$' + token.image); return new Variable(token.image,token.sourceStart,token.sourceEnd); } } Expression VariableInitializer() : { final Expression expr; final Token token, token2; } { expr = Literal() {return expr;} | token2 = (token = | token = ) {return new PrefixedUnaryExpression(new NumberLiteral(token), OperatorIds.MINUS, token2.sourceStart);} | token2 = (token = | token = ) {return new PrefixedUnaryExpression(new NumberLiteral(token), OperatorIds.PLUS, token2.sourceStart);} | expr = ArrayDeclarator() {return expr;} | token = {return new ConstantIdentifier(token);} } ArrayVariableDeclaration ArrayVariable() : { final Expression expr,expr2; } { expr = Expression() [ expr2 = Expression() {return new ArrayVariableDeclaration(expr,expr2);} ] {return new ArrayVariableDeclaration(expr,jj_input_stream.getPosition());} } ArrayVariableDeclaration[] ArrayInitializer() : { ArrayVariableDeclaration expr; final ArrayList list = new ArrayList(); } { [ expr = ArrayVariable() {list.add(expr);} ( LOOKAHEAD(2) expr = ArrayVariable() {list.add(expr);} )* ] [ {list.add(null);} ] { final ArrayVariableDeclaration[] vars = new ArrayVariableDeclaration[list.size()]; list.toArray(vars); return vars;} } /** * A Method Declaration. * function MetodDeclarator() Block() */ MethodDeclaration MethodDeclaration() : { final MethodDeclaration functionDeclaration; final Block block; final OutlineableWithChildren seg = currentSegment; final Token token; } { token = try { functionDeclaration = MethodDeclarator(token.sourceStart) {outlineInfo.addVariable(functionDeclaration.name);} } catch (ParseException e) { if (errorMessage != null) throw e; errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } {currentSegment = functionDeclaration;} block = Block() {functionDeclaration.statements = block.statements; currentSegment = seg; return functionDeclaration;} } /** * A MethodDeclarator. * [&] IDENTIFIER(parameters ...). * @return a function description for the outline */ MethodDeclaration MethodDeclarator(final int start) : { Token identifier = null; Token reference = null; final ArrayList formalParameters = new ArrayList(); String identifierChar = SYNTAX_ERROR_CHAR; int end = start; } { [reference = {end = reference.sourceEnd;}] try { identifier = { identifierChar = identifier.image; end = identifier.sourceEnd; } } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function identifier expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceEnd; errorEnd = e.currentToken.next.sourceStart; processParseExceptionDebug(e); } end = FormalParameters(formalParameters) { int nameStart, nameEnd; if (identifier == null) { if (reference == null) { nameStart = start + 9; nameEnd = start + 10; } else { nameStart = reference.sourceEnd + 1; nameEnd = reference.sourceEnd + 2; } } else { nameStart = identifier.sourceStart; nameEnd = identifier.sourceEnd; } return new MethodDeclaration(currentSegment, identifierChar, formalParameters, reference != null, nameStart, nameEnd, start, end); } } /** * FormalParameters follows method identifier. * (FormalParameter()) */ int FormalParameters(final ArrayList parameters) : { VariableDeclaration var; final Token token; Token tok = this.token; int end = tok.sourceEnd; } { try { tok = {end = tok.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected after function identifier"; errorLevel = ERROR; errorStart = e.currentToken.next.sourceStart; errorEnd = e.currentToken.next.sourceEnd; processParseExceptionDebug(e); } [ var = FormalParameter() {parameters.add(var);end = var.sourceEnd;} ( var = FormalParameter() {parameters.add(var);end = var.sourceEnd;} )* ] try { token = {end = token.sourceEnd;} } catch (ParseException e) { errorMessage = "')' expected"; errorLevel = ERROR; errorStart = e.currentToken.next.sourceStart; errorEnd = e.currentToken.next.sourceEnd; processParseExceptionDebug(e); } {return end;} } /** * A formal parameter. * $varname[=value] (,$varname[=value]) */ VariableDeclaration FormalParameter() : { final VariableDeclaration variableDeclaration; Token token = null; } { [token = ] variableDeclaration = VariableDeclaratorNoSuffix() { outlineInfo.addVariable('$'+variableDeclaration.name()); if (token != null) { variableDeclaration.setReference(true); } return variableDeclaration;} } ConstantIdentifier Type() : {final Token token;} { token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} | token = {return new ConstantIdentifier(token);} } Expression Expression() : { final Expression expr; Expression initializer = null; int assignOperator = -1; } { LOOKAHEAD(1) expr = ConditionalExpression() [ assignOperator = AssignmentOperator() try { initializer = Expression() } catch (ParseException e) { if (errorMessage != null) { throw e; } errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected"; errorLevel = ERROR; errorEnd = jj_input_stream.getPosition(); throw e; } ] { if (assignOperator != -1) {// todo : change this, very very bad :( if (expr instanceof AbstractVariable) { return new VariableDeclaration(currentSegment, (AbstractVariable) expr, initializer, expr.sourceStart, initializer.sourceEnd); } String varName = expr.toStringExpression().substring(1); return new VariableDeclaration(currentSegment, new Variable(varName, expr.sourceStart, expr.sourceEnd), expr.sourceStart, initializer.sourceEnd); } return expr; } | expr = ExpressionWBang() {return expr;} } Expression ExpressionWBang() : { final Expression expr; final Token token; } { token = expr = ExpressionWBang() {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);} | expr = ExpressionNoBang() {return expr;} } Expression ExpressionNoBang() : { Expression expr; } { expr = ListExpression() {return expr;} | expr = PrintExpression() {return expr;} } /** * Any assignement operator. * @return the assignement operator id */ int AssignmentOperator() : {} { {return VariableDeclaration.EQUAL;} | {return VariableDeclaration.STAR_EQUAL;} | {return VariableDeclaration.SLASH_EQUAL;} | {return VariableDeclaration.REM_EQUAL;} | {return VariableDeclaration.PLUS_EQUAL;} | {return VariableDeclaration.MINUS_EQUAL;} | {return VariableDeclaration.LSHIFT_EQUAL;} | {return VariableDeclaration.RSIGNEDSHIFT_EQUAL;} | {return VariableDeclaration.AND_EQUAL;} | {return VariableDeclaration.XOR_EQUAL;} | {return VariableDeclaration.OR_EQUAL;} | {return VariableDeclaration.DOT_EQUAL;} | {return VariableDeclaration.TILDE_EQUAL;} } Expression ConditionalExpression() : { final Expression expr; Expression expr2 = null; Expression expr3 = null; } { expr = ConditionalOrExpression() [ expr2 = Expression() expr3 = ConditionalExpression() ] { if (expr3 == null) { return expr; } return new ConditionalExpression(expr,expr2,expr3); } } Expression ConditionalOrExpression() : { Expression expr,expr2; int operator; } { expr = ConditionalAndExpression() ( ( {operator = OperatorIds.OR_OR;} | <_ORL> {operator = OperatorIds.ORL;} ) expr2 = ConditionalAndExpression() { expr = new BinaryExpression(expr,expr2,operator); } )* {return expr;} } Expression ConditionalAndExpression() : { Expression expr,expr2; int operator; } { expr = ConcatExpression() ( ( {operator = OperatorIds.AND_AND;} | <_ANDL> {operator = OperatorIds.ANDL;}) expr2 = ConcatExpression() {expr = new BinaryExpression(expr,expr2,operator);} )* {return expr;} } Expression ConcatExpression() : { Expression expr,expr2; } { expr = InclusiveOrExpression() ( expr2 = InclusiveOrExpression() {expr = new BinaryExpression(expr,expr2,OperatorIds.DOT);} )* {return expr;} } Expression InclusiveOrExpression() : { Expression expr,expr2; } { expr = ExclusiveOrExpression() ( expr2 = ExclusiveOrExpression() {expr = new BinaryExpression(expr,expr2,OperatorIds.OR);} )* {return expr;} } Expression ExclusiveOrExpression() : { Expression expr,expr2; } { expr = AndExpression() ( expr2 = AndExpression() {expr = new BinaryExpression(expr,expr2,OperatorIds.XOR);} )* {return expr;} } Expression AndExpression() : { Expression expr,expr2; } { expr = EqualityExpression() ( LOOKAHEAD(1) expr2 = EqualityExpression() {expr = new BinaryExpression(expr,expr2,OperatorIds.AND);} )* {return expr;} } Expression EqualityExpression() : { Expression expr,expr2; int operator; Token token; } { expr = RelationalExpression() ( ( token = {operator = OperatorIds.EQUAL_EQUAL;} | token = {operator = OperatorIds.DIF;} | token = {operator = OperatorIds.DIF;} | token = {operator = OperatorIds.BANG_EQUAL_EQUAL;} | token = {operator = OperatorIds.EQUAL_EQUAL_EQUAL;} ) try { expr2 = RelationalExpression() } catch (ParseException e) { if (errorMessage != null) { throw e; } errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected"; errorLevel = ERROR; errorStart = token.sourceEnd +1; errorEnd = token.sourceEnd +1; expr2 = new ConstantIdentifier(SYNTAX_ERROR_CHAR,token.sourceEnd +1,token.sourceEnd +1); processParseExceptionDebug(e); } { expr = new BinaryExpression(expr,expr2,operator); } )* {return expr;} } Expression RelationalExpression() : { Expression expr,expr2; int operator; } { expr = ShiftExpression() ( ( {operator = OperatorIds.LESS;} | {operator = OperatorIds.GREATER;} | {operator = OperatorIds.LESS_EQUAL;} | {operator = OperatorIds.GREATER_EQUAL;}) expr2 = ShiftExpression() {expr = new BinaryExpression(expr,expr2,operator);} )* {return expr;} } Expression ShiftExpression() : { Expression expr,expr2; int operator; } { expr = AdditiveExpression() ( ( {operator = OperatorIds.LEFT_SHIFT;} | {operator = OperatorIds.RIGHT_SHIFT;} | {operator = OperatorIds.UNSIGNED_RIGHT_SHIFT;}) expr2 = AdditiveExpression() {expr = new BinaryExpression(expr,expr2,operator);} )* {return expr;} } Expression AdditiveExpression() : { Expression expr,expr2; int operator; } { expr = MultiplicativeExpression() ( LOOKAHEAD(1) ( {operator = OperatorIds.PLUS;} | {operator = OperatorIds.MINUS;} ) expr2 = MultiplicativeExpression() {expr = new BinaryExpression(expr,expr2,operator);} )* {return expr;} } Expression MultiplicativeExpression() : { Expression expr,expr2; int operator; } { try { expr = UnaryExpression() } catch (ParseException e) { if (errorMessage != null) throw e; errorMessage = "unexpected token '"+e.currentToken.next.image+'\''; errorLevel = ERROR; errorStart = this.token.sourceStart; errorEnd = this.token.sourceEnd; throw e; } ( ( {operator = OperatorIds.MULTIPLY;} | {operator = OperatorIds.DIVIDE;} | {operator = OperatorIds.REMAINDER;}) expr2 = UnaryExpression() {expr = new BinaryExpression(expr,expr2,operator);} )* {return expr;} } /** * An unary expression starting with @, & or nothing */ Expression UnaryExpression() : { final Expression expr; } { /* expr = UnaryExpressionNoPrefix() //why did I had that ? {return new PrefixedUnaryExpression(expr,OperatorIds.AND,pos);} | */ expr = AtNotTildeUnaryExpression() {return expr;} } Expression AtNotTildeUnaryExpression() : { final Expression expr; final Token token; } { token = expr = AtNotTildeUnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.AT,token.sourceStart);} | token = expr = AtNotTildeUnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.TWIDDLE,token.sourceStart);} | token = expr = AtNotUnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);} | expr = UnaryExpressionNoPrefix() {return expr;} } /** * An expression prefixed (or not) by one or more @ and !. * @return the expression */ Expression AtNotUnaryExpression() : { final Expression expr; final Token token; } { token = expr = AtNotUnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.AT,token.sourceStart);} | token = expr = AtNotUnaryExpression() {return new PrefixedUnaryExpression(expr,OperatorIds.NOT,token.sourceStart);} | expr = UnaryExpressionNoPrefix() {return expr;} } Expression UnaryExpressionNoPrefix() : { final Expression expr; final Token token; } { token = expr = AtNotTildeUnaryExpression() {return new PrefixedUnaryExpression(expr, OperatorIds.PLUS, token.sourceStart);} | token = expr = AtNotTildeUnaryExpression() {return new PrefixedUnaryExpression(expr, OperatorIds.MINUS, token.sourceStart);} | expr = PreIncDecExpression() {return expr;} | expr = UnaryExpressionNotPlusMinus() {return expr;} } Expression PreIncDecExpression() : { final Expression expr; final int operator; final Token token; } { ( token = {operator = OperatorIds.PLUS_PLUS;} | token = {operator = OperatorIds.MINUS_MINUS;} ) expr = PrimaryExpression() {return new PrefixedUnaryExpression(expr,operator,token.sourceStart);} } Expression UnaryExpressionNotPlusMinus() : { final Expression expr; } { LOOKAHEAD( (Type() | ) ) expr = CastExpression() {return expr;} | expr = PostfixExpression() {return expr;} | expr = Literal() {return expr;} | expr = Expression() try { } catch (ParseException e) { errorMessage = "')' expected"; errorLevel = ERROR; errorStart = expr.sourceEnd +1; errorEnd = expr.sourceEnd +1; processParseExceptionDebug(e); } {return expr;} } CastExpression CastExpression() : { final ConstantIdentifier type; final Expression expr; final Token token,token1; } { token1 = ( type = Type() | token = {type = new ConstantIdentifier(token);} ) expr = UnaryExpression() {return new CastExpression(type,expr,token1.sourceStart,expr.sourceEnd);} } Expression PostfixExpression() : { final Expression expr; int operator = -1; Token token = null; } { expr = PrimaryExpression() [ token = {operator = OperatorIds.PLUS_PLUS;} | token = {operator = OperatorIds.MINUS_MINUS;} ] { if (operator == -1) { return expr; } return new PostfixedUnaryExpression(expr,operator,token.sourceEnd); } } Expression PrimaryExpression() : { Expression expr; Token token = null; } { [token = ] expr = refPrimaryExpression(token) {return expr;} | expr = ArrayDeclarator() {return expr;} } Expression refPrimaryExpression(final Token reference) : { Expression expr; Expression expr2 = null; final Token identifier; } { identifier = { expr = new ConstantIdentifier(identifier); } ( expr2 = ClassIdentifier() {expr = new ClassAccess(expr, expr2, ClassAccess.STATIC);} )* [ expr2 = Arguments(expr) ] { if (expr2 == null) { if (reference != null) { ParseException e = generateParseException(); errorMessage = "you cannot use a constant by reference"; errorLevel = ERROR; errorStart = reference.sourceStart; errorEnd = reference.sourceEnd; processParseExceptionDebug(e); } return expr; } return expr2; } | expr = VariableDeclaratorId() //todo use the reference parameter ... [ expr = Arguments(expr) ] {return expr;} | token = expr = ClassIdentifier() { int start; if (reference == null) { start = token.sourceStart; } else { start = reference.sourceStart; } expr = new ClassInstantiation(expr, reference != null, start); } [ expr = Arguments(expr) ] {return expr;} } /** * An array declarator. * array(vars) * @return an array */ ArrayInitializer ArrayDeclarator() : { final ArrayVariableDeclaration[] vars; final Token token; } { token = vars = ArrayInitializer() {return new ArrayInitializer(vars, token.sourceStart, this.token.sourceEnd);} } Expression ClassIdentifier(): { final Expression expr; final Token token; } { token = {return new ConstantIdentifier(token);} | expr = Type() {return expr;} | expr = VariableDeclaratorId() {return expr;} } /** * Used by Variabledeclaratorid and primarysuffix */ AbstractVariable VariableSuffix(final AbstractVariable prefix) : { Expression expression = null; final Token classAccessToken,lbrace,rbrace; Token token; int pos; } { classAccessToken = try { ( lbrace = expression = Expression() rbrace = { expression = new Variable(expression, lbrace.sourceStart, rbrace.sourceEnd); } | token = {expression = new ConstantIdentifier(token.image,token.sourceStart,token.sourceEnd);} | expression = Variable() ) } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', function call or field access expected"; errorLevel = ERROR; errorStart = classAccessToken.sourceEnd +1; errorEnd = classAccessToken.sourceEnd +1; processParseExceptionDebug(e); } {return new ClassAccess(prefix, expression, ClassAccess.NORMAL);} | token = {pos = token.sourceEnd+1;} [ expression = Expression() {pos = expression.sourceEnd+1;} | expression = Type() {pos = expression.sourceEnd+1;}] //Not good try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "']' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } {return new ArrayDeclarator(prefix,expression,pos);} | token = {pos = token.sourceEnd+1;} [ expression = Expression() {pos = expression.sourceEnd+1;} | expression = Type() {pos = expression.sourceEnd+1;}] //Not good try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "']' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } {return new ArrayDeclarator(prefix,expression,pos);}//todo : check braces here } Literal Literal() : { final Token token; StringLiteral literal; } { token = {return new NumberLiteral(token);} | token = {return new NumberLiteral(token);} | token = {return new StringLiteral(token);} | token = {return new TrueLiteral(token);} | token = {return new FalseLiteral(token);} | token = {return new NullLiteral(token);} | literal = evaluableString() {return literal;} } StringLiteral evaluableString() : { ArrayList list = new ArrayList(); Token start,end; Token token,lbrace,rbrace; AbstractVariable var; Expression expr; } { start = ( ( token = {list.add(new Variable(token.image, token.sourceStart, token.sourceEnd));} | lbrace = token = {list.add(new Variable(token.image, token.sourceStart, token.sourceEnd));} rbrace = ) )* end = { AbstractVariable[] vars = new AbstractVariable[list.size()]; list.toArray(vars); return new StringLiteral(jj_input_stream.getCurrentBuffer().substring(start.sourceEnd,end.sourceStart), start.sourceStart, end.sourceEnd, vars); } } FunctionCall Arguments(final Expression func) : { Expression[] args = null; final Token token,lparen; } { lparen = [ args = ArgumentList() ] try { token = {return new FunctionCall(func,args,token.sourceEnd);} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected to close the argument list"; errorLevel = ERROR; if (args == null) { errorStart = lparen.sourceEnd+1; errorEnd = lparen.sourceEnd+2; } else { errorStart = args[args.length-1].sourceEnd+1; errorEnd = args[args.length-1].sourceEnd+2; } processParseExceptionDebug(e); } { int sourceEnd = (args == null && args.length != 0) ? lparen.sourceEnd+1 : args[args.length-1].sourceEnd; return new FunctionCall(func,args,sourceEnd);} } /** * An argument list is a list of arguments separated by comma : * argumentDeclaration() (, argumentDeclaration)* * @return an array of arguments */ Expression[] ArgumentList() : { Expression arg; final ArrayList list = new ArrayList(); int pos; Token token; } { arg = Expression() {list.add(arg);pos = arg.sourceEnd;} ( token = {pos = token.sourceEnd;} try { arg = Expression() {list.add(arg); pos = arg.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. An expression expected after a comma in argument list"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseException(e); } )* { final Expression[] arguments = new Expression[list.size()]; list.toArray(arguments); return arguments;} } /** * A Statement without break. * @return a statement */ Statement StatementNoBreak() : { final Statement statement; Token token = null; } { LOOKAHEAD(2) statement = expressionStatement() {return statement;} | LOOKAHEAD(1) statement = LabeledStatement() {return statement;} | statement = Block() {return statement;} | statement = EmptyStatement() {return statement;} | statement = SwitchStatement() {return statement;} | statement = IfStatement() {return statement;} | statement = WhileStatement() {return statement;} | statement = DoStatement() {return statement;} | statement = ForStatement() {return statement;} | statement = ForeachStatement() {return statement;} | statement = ContinueStatement() {return statement;} | statement = ReturnStatement() {return statement;} | statement = EchoStatement() {return statement;} | [token=] statement = IncludeStatement() {if (token != null) { ((InclusionStatement)statement).silent = true; statement.sourceStart = token.sourceStart; } return statement;} | statement = StaticStatement() {return statement;} | statement = GlobalStatement() {return statement;} | statement = defineStatement() {currentSegment.add((Outlineable)statement);return statement;} } /** * A statement expression. * expression ; * @return an expression */ Statement expressionStatement() : { final Statement statement; final Token token; } { statement = Expression() try { token = {statement.sourceEnd = token.sourceEnd;} } catch (ParseException e) { if (e.currentToken.next.kind != PHPParserConstants.PHPEND) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected"; errorLevel = ERROR; errorStart = statement.sourceEnd+1; errorEnd = statement.sourceEnd+1; processParseExceptionDebug(e); } } {return statement;} } Define defineStatement() : { Expression defineName,defineValue; final Token defineToken; Token token; int pos; } { defineToken = {pos = defineToken.sourceEnd+1;} try { token = {pos = token.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } try { defineName = Expression() {pos = defineName.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); defineName = new StringLiteral(SYNTAX_ERROR_CHAR,pos,pos); } try { token = {pos = defineName.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } try { defineValue = Expression() {pos = defineValue.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', expression expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); defineValue = new StringLiteral(SYNTAX_ERROR_CHAR,pos,pos); } try { token = {pos = token.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } {return new Define(currentSegment, defineName, defineValue, defineToken.sourceStart, pos);} } /** * A Normal statement. */ Statement Statement() : { final Statement statement; } { statement = StatementNoBreak() {return statement;} | statement = BreakStatement() {return statement;} } /** * An html block inside a php syntax. */ HTMLBlock htmlBlock() : { final int startIndex = nodePtr; final AstNode[] blockNodes; final int nbNodes; final Token phpEnd; } { phpEnd = {htmlStart = phpEnd.sourceEnd;} (phpEchoBlock())* try { ( | ) {createNewHTMLCode();} } catch (ParseException e) { errorMessage = "unexpected end of file , ' {keyword = InclusionStatement.REQUIRE;pos=token.sourceEnd;} | token = {keyword = InclusionStatement.REQUIRE_ONCE;pos=token.sourceEnd;} | token = {keyword = InclusionStatement.INCLUDE;pos=token.sourceEnd;} | token = {keyword = InclusionStatement.INCLUDE_ONCE;pos=token.sourceEnd;}) try { expr = Expression() {pos = expr.sourceEnd;} } catch (ParseException e) { if (errorMessage != null) { throw e; } errorMessage = "unexpected token '"+ e.currentToken.next.image+"', expression expected"; errorLevel = ERROR; errorStart = e.currentToken.next.sourceStart; errorEnd = e.currentToken.next.sourceEnd; expr = new ConstantIdentifier(SYNTAX_ERROR_CHAR,pos,pos); processParseExceptionDebug(e); } try { token2 = {pos=token2.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected"; errorLevel = ERROR; errorStart = e.currentToken.next.sourceStart; errorEnd = e.currentToken.next.sourceEnd; processParseExceptionDebug(e); } { inclusionStatement = new InclusionStatement(currentSegment, keyword, expr, token.sourceStart, pos); currentSegment.add(inclusionStatement); return inclusionStatement; } } PrintExpression PrintExpression() : { final Expression expr; final Token printToken; } { token = expr = Expression() {return new PrintExpression(expr,token.sourceStart,expr.sourceEnd);} } ListExpression ListExpression() : { Expression expr = null; final Expression expression; final ArrayList list = new ArrayList(); int pos; final Token listToken, rParen; Token token; } { listToken = {pos = listToken.sourceEnd;} try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', '(' expected"; errorLevel = ERROR; errorStart = listToken.sourceEnd+1; errorEnd = listToken.sourceEnd+1; processParseExceptionDebug(e); } [ expr = VariableDeclaratorId() {list.add(expr);pos = expr.sourceEnd;} ] {if (expr == null) list.add(null);} ( try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ',' expected"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseExceptionDebug(e); } [expr = VariableDeclaratorId() {list.add(expr);pos = expr.sourceEnd;}] )* try { rParen = {pos = rParen.sourceEnd;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"', ')' expected"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseExceptionDebug(e); } [ expression = Expression() { final AbstractVariable[] vars = new AbstractVariable[list.size()]; list.toArray(vars); return new ListExpression(vars, expression, listToken.sourceStart, expression.sourceEnd);} ] { final AbstractVariable[] vars = new AbstractVariable[list.size()]; list.toArray(vars); return new ListExpression(vars,listToken.sourceStart,pos);} } /** * An echo statement. * echo anyexpression (, otherexpression)* */ EchoStatement EchoStatement() : { final ArrayList expressions = new ArrayList(); Expression expr; Token token; Token token2 = null; } { token = expr = Expression() {expressions.add(expr);} ( expr = Expression() {expressions.add(expr);} )* try { token2 = } catch (ParseException e) { if (e.currentToken.next.kind != 4) { errorMessage = "';' expected after 'echo' statement"; errorLevel = ERROR; errorStart = e.currentToken.sourceEnd; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } } { final Expression[] exprs = new Expression[expressions.size()]; expressions.toArray(exprs); if (token2 == null) { return new EchoStatement(exprs,token.sourceStart, exprs[exprs.length-1].sourceEnd); } return new EchoStatement(exprs,token.sourceStart, token2.sourceEnd); } } GlobalStatement GlobalStatement() : { Variable expr; final ArrayList vars = new ArrayList(); final GlobalStatement global; final Token token, token2; int pos; } { token = expr = Variable() {vars.add(expr);pos = expr.sourceEnd+1;} ( expr = Variable() {vars.add(expr);pos = expr.sourceEnd+1;} )* try { token2 = {pos = token2.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } { final Variable[] variables = new Variable[vars.size()]; vars.toArray(variables); global = new GlobalStatement(currentSegment, variables, token.sourceStart, pos); currentSegment.add(global); return global;} } StaticStatement StaticStatement() : { final ArrayList vars = new ArrayList(); VariableDeclaration expr; final Token token, token2; int pos; } { token = expr = VariableDeclarator() {vars.add(expr);pos = expr.sourceEnd+1;} ( expr = VariableDeclarator() {vars.add(expr);pos = expr.sourceEnd+1;} )* try { token2 = {pos = token2.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. a ';' was expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseException(e); } { final VariableDeclaration[] variables = new VariableDeclaration[vars.size()]; vars.toArray(variables); return new StaticStatement(variables, token.sourceStart, pos);} } LabeledStatement LabeledStatement() : { final Token label; final Statement statement; } { label = statement = Statement() {return new LabeledStatement(label.image,statement,label.sourceStart,statement.sourceEnd);} } /** * A Block is * { * statements * }. * @return a block */ Block Block() : { final ArrayList list = new ArrayList(); Statement statement; final Token token, token2; int pos,start; } { try { token = {pos = token.sourceEnd+1;start=token.sourceStart;} } catch (ParseException e) { errorMessage = "'{' expected"; errorLevel = ERROR; pos = this.token.sourceEnd+1; start=pos; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } ( statement = BlockStatement() {list.add(statement);pos = statement.sourceEnd+1;} | statement = htmlBlock() {if (statement != null) { list.add(statement); pos = statement.sourceEnd+1; } pos = this.token.sourceEnd+1; } )* try { token2 = {pos = token2.sourceEnd+1;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.image +"', '}' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } { final Statement[] statements = new Statement[list.size()]; list.toArray(statements); return new Block(statements,start,pos);} } Statement BlockStatement() : { final Statement statement; } { try { statement = Statement() {if (phpDocument == currentSegment) pushOnAstNodes(statement); return statement;} } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.image +"', a statement was expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } | statement = ClassDeclaration() {return statement;} | statement = MethodDeclaration() {if (phpDocument == currentSegment) pushOnAstNodes(statement); currentSegment.add((MethodDeclaration) statement); ((MethodDeclaration) statement).analyzeCode(); return statement;} } /** * A Block statement that will not contain any 'break' */ Statement BlockStatementNoBreak() : { final Statement statement; } { statement = StatementNoBreak() {return statement;} | statement = ClassDeclaration() {return statement;} | statement = MethodDeclaration() {currentSegment.add((MethodDeclaration) statement); ((MethodDeclaration) statement).analyzeCode(); return statement;} } /** * used only by ForInit() */ Expression[] LocalVariableDeclaration() : { final ArrayList list = new ArrayList(); Expression var; } { var = Expression() {list.add(var);} ( var = Expression() {list.add(var);})* { final Expression[] vars = new Expression[list.size()]; list.toArray(vars); return vars; } } /** * used only by LocalVariableDeclaration(). */ VariableDeclaration LocalVariableDeclarator() : { final Variable varName; Expression initializer = null; } { varName = Variable() [ initializer = Expression() ] { if (initializer == null) { return new VariableDeclaration(currentSegment, varName, varName.sourceStart, varName.sourceEnd); } return new VariableDeclaration(currentSegment, varName, initializer, VariableDeclaration.EQUAL, varName.sourceStart); } } EmptyStatement EmptyStatement() : { final Token token; } { token = {return new EmptyStatement(token.sourceStart,token.sourceEnd);} } /** * used only by StatementExpressionList() which is used only by ForInit() and ForStatement() */ Expression StatementExpression() : { final Expression expr; final Token operator; } { expr = PreIncDecExpression() {return expr;} | expr = PrimaryExpression() [ operator = {return new PostfixedUnaryExpression(expr, OperatorIds.PLUS_PLUS, operator.sourceEnd);} | operator = {return new PostfixedUnaryExpression(expr, OperatorIds.MINUS_MINUS, operator.sourceEnd);} ] {return expr;} } SwitchStatement SwitchStatement() : { Expression variable; final AbstractCase[] cases; final Token switchToken,lparenToken,rparenToken; int pos; } { switchToken = {pos = switchToken.sourceEnd+1;} try { lparenToken = {pos = lparenToken.sourceEnd+1;} } catch (ParseException e) { errorMessage = "'(' expected after 'switch'"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } try { variable = Expression() {pos = variable.sourceEnd+1;} } catch (ParseException e) { if (errorMessage != null) { throw e; } errorMessage = "expression expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); variable = new ConstantIdentifier(SYNTAX_ERROR_CHAR,pos,pos); } try { rparenToken = {pos = rparenToken.sourceEnd+1;} } catch (ParseException e) { errorMessage = "')' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } ( cases = switchStatementBrace() | cases = switchStatementColon(switchToken.sourceStart, switchToken.sourceEnd)) {return new SwitchStatement(variable, cases, switchToken.sourceStart, this.token.sourceEnd);} } AbstractCase[] switchStatementBrace() : { AbstractCase cas; final ArrayList cases = new ArrayList(); Token token; int pos; } { token = {pos = token.sourceEnd;} ( cas = switchLabel0() {cases.add(cas);pos = cas.sourceEnd;})* try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "'}' expected"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseExceptionDebug(e); } { final AbstractCase[] abcase = new AbstractCase[cases.size()]; cases.toArray(abcase); return abcase; } } /** * A Switch statement with : ... endswitch; * @param start the begin offset of the switch * @param end the end offset of the switch */ AbstractCase[] switchStatementColon(final int start, final int end) : { AbstractCase cas; final ArrayList cases = new ArrayList(); Token token; int pos; } { token = {pos = token.sourceEnd;} {try { setMarker(fileToParse, "Ugly syntax detected, you should switch () {...} instead of switch (): ... enswitch;", start, end, INFO, "Line " + token.beginLine); } catch (CoreException e) { PHPeclipsePlugin.log(e); }} ( cas = switchLabel0() {cases.add(cas);pos = cas.sourceEnd;})* try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "'endswitch' expected"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseExceptionDebug(e); } try { token = {pos = token.sourceEnd;} } catch (ParseException e) { errorMessage = "';' expected after 'endswitch' keyword"; errorLevel = ERROR; errorStart = pos+1; errorEnd = pos+1; processParseExceptionDebug(e); } { final AbstractCase[] abcase = new AbstractCase[cases.size()]; cases.toArray(abcase); return abcase; } } AbstractCase switchLabel0() : { final Expression expr; Statement statement; final ArrayList stmts = new ArrayList(); final Token token = this.token; final int start = this.token.next.sourceStart; } { expr = SwitchLabel() ( statement = BlockStatementNoBreak() {stmts.add(statement);} | statement = htmlBlock() {if (statement != null) {stmts.add(statement);}} | statement = BreakStatement() {stmts.add(statement);})* //[ statement = BreakStatement() {stmts.add(statement);}] { final int listSize = stmts.size(); final Statement[] stmtsArray = new Statement[listSize]; stmts.toArray(stmtsArray); if (expr == null) {//it's a default final int end = this.token.next.sourceStart; return new DefaultCase(stmtsArray,start,end); } if (listSize != 0) { return new Case(expr,stmtsArray,expr.sourceStart,stmtsArray[listSize-1].sourceEnd); } else { return new Case(expr,stmtsArray,expr.sourceStart,expr.sourceEnd); } } } /** * A SwitchLabel. * case Expression() : * default : * @return the if it was a case and null if not */ Expression SwitchLabel() : { final Expression expr; } { token = try { expr = Expression() } catch (ParseException e) { if (errorMessage != null) throw e; errorMessage = "expression expected after 'case' keyword"; errorLevel = ERROR; errorStart = token.sourceEnd +1; errorEnd = token.sourceEnd +1; throw e; } try { token = } catch (ParseException e) { errorMessage = "':' expected after case expression"; errorLevel = ERROR; errorStart = expr.sourceEnd+1; errorEnd = expr.sourceEnd+1; processParseExceptionDebug(e); } {return expr;} | token = <_DEFAULT> try { } catch (ParseException e) { errorMessage = "':' expected after 'default' keyword"; errorLevel = ERROR; errorStart = token.sourceEnd+1; errorEnd = token.sourceEnd+1; processParseExceptionDebug(e); } {return null;} } Break BreakStatement() : { Expression expression = null; final Token token, token2; int pos; } { token = {pos = token.sourceEnd+1;} [ expression = Expression() {pos = expression.sourceEnd+1;}] try { token2 = {pos = token2.sourceEnd;} } catch (ParseException e) { errorMessage = "';' expected after 'break' keyword"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } {return new Break(expression, token.sourceStart, pos);} } IfStatement IfStatement() : { final Expression condition; final IfStatement ifStatement; Token token; } { token = condition = Condition("if") ifStatement = IfStatement0(condition,token.sourceStart,token.sourceEnd) {return ifStatement;} } Expression Condition(final String keyword) : { final Expression condition; } { try { } catch (ParseException e) { errorMessage = "'(' expected after " + keyword + " keyword"; errorLevel = ERROR; errorStart = this.token.sourceEnd + 1; errorEnd = this.token.sourceEnd + 1; processParseExceptionDebug(e); } condition = Expression() try { } catch (ParseException e) { errorMessage = "')' expected after " + keyword + " keyword"; errorLevel = ERROR; errorStart = condition.sourceEnd+1; errorEnd = condition.sourceEnd+1; processParseExceptionDebug(e); } {return condition;} } IfStatement IfStatement0(final Expression condition, final int start,final int end) : { Statement statement; final Statement stmt; final Statement[] statementsArray; ElseIf elseifStatement; Else elseStatement = null; final ArrayList stmts; final ArrayList elseIfList = new ArrayList(); final ElseIf[] elseIfs; int pos = jj_input_stream.getPosition(); final int endStatements; } { {stmts = new ArrayList();} ( statement = Statement() {stmts.add(statement);} | statement = htmlBlock() {if (statement != null) {stmts.add(statement);}})* {endStatements = jj_input_stream.getPosition();} (elseifStatement = ElseIfStatementColon() {elseIfList.add(elseifStatement);})* [elseStatement = ElseStatementColon()] {try { setMarker(fileToParse, "Ugly syntax detected, you should if () {...} instead of if (): ... endif;", start, end, INFO, "Line " + token.beginLine); } catch (CoreException e) { PHPeclipsePlugin.log(e); }} try { } catch (ParseException e) { errorMessage = "'endif' expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } try { } catch (ParseException e) { errorMessage = "';' expected after 'endif' keyword"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } { elseIfs = new ElseIf[elseIfList.size()]; elseIfList.toArray(elseIfs); if (stmts.size() == 1) { return new IfStatement(condition, (Statement) stmts.get(0), elseIfs, elseStatement, pos, jj_input_stream.getPosition()); } else { statementsArray = new Statement[stmts.size()]; stmts.toArray(statementsArray); return new IfStatement(condition, new Block(statementsArray,pos,endStatements), elseIfs, elseStatement, pos, jj_input_stream.getPosition()); } } | (stmt = Statement() | stmt = htmlBlock()) ( LOOKAHEAD(1) elseifStatement = ElseIfStatement() {elseIfList.add(elseifStatement);})* [ LOOKAHEAD(1) try { {pos = jj_input_stream.getPosition();} statement = Statement() {elseStatement = new Else(statement,pos,jj_input_stream.getPosition());} } catch (ParseException e) { if (errorMessage != null) { throw e; } errorMessage = "unexpected token '"+e.currentToken.next.image+"', a statement was expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } ] { elseIfs = new ElseIf[elseIfList.size()]; elseIfList.toArray(elseIfs); return new IfStatement(condition, stmt, elseIfs, elseStatement, pos, jj_input_stream.getPosition());} } ElseIf ElseIfStatementColon() : { final Expression condition; Statement statement; final ArrayList list = new ArrayList(); final Token elseifToken; } { elseifToken = condition = Condition("elseif") ( statement = Statement() {list.add(statement);} | statement = htmlBlock() {if (statement != null) {list.add(statement);}})* { final int sizeList = list.size(); final Statement[] stmtsArray = new Statement[sizeList]; list.toArray(stmtsArray); return new ElseIf(condition,stmtsArray , elseifToken.sourceStart, stmtsArray[sizeList-1].sourceEnd);} } Else ElseStatementColon() : { Statement statement; final ArrayList list = new ArrayList(); final Token elseToken; } { elseToken = ( statement = Statement() {list.add(statement);} | statement = htmlBlock() {if (statement != null) {list.add(statement);}})* { final int sizeList = list.size(); final Statement[] stmtsArray = new Statement[sizeList]; list.toArray(stmtsArray); return new Else(stmtsArray,elseToken.sourceStart,stmtsArray[sizeList-1].sourceEnd);} } ElseIf ElseIfStatement() : { final Expression condition; //final Statement statement; final Token elseifToken; final Statement[] statement = new Statement[1]; } { elseifToken = condition = Condition("elseif") statement[0] = Statement() { return new ElseIf(condition,statement,elseifToken.sourceStart,statement[0].sourceEnd);} } WhileStatement WhileStatement() : { final Expression condition; final Statement action; final Token whileToken; } { whileToken = condition = Condition("while") action = WhileStatement0(whileToken.sourceStart,whileToken.sourceEnd) {return new WhileStatement(condition,action,whileToken.sourceStart,action.sourceEnd);} } Statement WhileStatement0(final int start, final int end) : { Statement statement; final ArrayList stmts = new ArrayList(); final int pos = jj_input_stream.getPosition(); } { (statement = Statement() {stmts.add(statement);})* {try { setMarker(fileToParse, "Ugly syntax detected, you should while () {...} instead of while (): ... endwhile;", start, end, INFO, "Line " + token.beginLine); } catch (CoreException e) { PHPeclipsePlugin.log(e); }} try { } catch (ParseException e) { errorMessage = "'endwhile' expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } try { { final Statement[] stmtsArray = new Statement[stmts.size()]; stmts.toArray(stmtsArray); return new Block(stmtsArray,pos,jj_input_stream.getPosition());} } catch (ParseException e) { errorMessage = "';' expected after 'endwhile' keyword"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; throw e; } | statement = Statement() {return statement;} } DoStatement DoStatement() : { final Statement action; final Expression condition; final Token token; Token token2 = null; } { token = action = Statement() condition = Condition("while") try { token2 = } catch (ParseException e) { errorMessage = "unexpected token : '"+ e.currentToken.next.image +"'. A ';' was expected"; errorLevel = ERROR; errorStart = condition.sourceEnd+1; errorEnd = condition.sourceEnd+1; processParseExceptionDebug(e); } { if (token2 == null) { return new DoStatement(condition,action,token.sourceStart,condition.sourceEnd); } return new DoStatement(condition,action,token.sourceStart,token2.sourceEnd); } } ForeachStatement ForeachStatement() : { Statement statement = null; Expression expression = null; ArrayVariableDeclaration variable = null; Token foreachToken; Token lparenToken = null; Token asToken = null; Token rparenToken = null; int pos; } { foreachToken = try { lparenToken = {pos = lparenToken.sourceEnd+1;} } catch (ParseException e) { errorMessage = "'(' expected after 'foreach' keyword"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); {pos = foreachToken.sourceEnd+1;} } try { expression = Expression() {pos = expression.sourceEnd+1;} } catch (ParseException e) { errorMessage = "variable expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } try { asToken = {pos = asToken.sourceEnd+1;} } catch (ParseException e) { errorMessage = "'as' expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } try { variable = ArrayVariable() {pos = variable.sourceEnd+1;} } catch (ParseException e) { if (errorMessage != null) throw e; errorMessage = "variable expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } try { rparenToken = {pos = rparenToken.sourceEnd+1;} } catch (ParseException e) { errorMessage = "')' expected after 'foreach' keyword"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } try { statement = Statement() {pos = statement.sourceEnd+1;} } catch (ParseException e) { if (errorMessage != null) throw e; errorMessage = "statement expected"; errorLevel = ERROR; errorStart = e.currentToken.sourceStart; errorEnd = e.currentToken.sourceEnd; processParseExceptionDebug(e); } { return new ForeachStatement(expression, variable, statement, foreachToken.sourceStart, pos);} } /** * a for declaration. * @return a node representing the for statement */ ForStatement ForStatement() : { final Token token,tokenEndFor,token2,tokenColon; int pos; Expression[] initializations = null; Expression condition = null; Expression[] increments = null; Statement action; final ArrayList list = new ArrayList(); } { token = try { } catch (ParseException e) { errorMessage = "'(' expected after 'for' keyword"; errorLevel = ERROR; errorStart = token.sourceEnd; errorEnd = token.sourceEnd +1; processParseExceptionDebug(e); } [ initializations = ForInit() ] [ condition = Expression() ] [ increments = StatementExpressionList() ] ( action = Statement() {return new ForStatement(initializations, condition, increments, action, token.sourceStart, action.sourceEnd);} | tokenColon = {pos = tokenColon.sourceEnd+1;} (action = Statement() {list.add(action);pos = action.sourceEnd+1;})* { try { setMarker(fileToParse, "Ugly syntax detected, you should for () {...} instead of for (): ... endfor;", token.sourceStart, token.sourceEnd, INFO, "Line " + token.beginLine); } catch (CoreException e) { PHPeclipsePlugin.log(e); } } try { tokenEndFor = {pos = tokenEndFor.sourceEnd+1;} } catch (ParseException e) { errorMessage = "'endfor' expected"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } try { token2 = {pos = token2.sourceEnd+1;} } catch (ParseException e) { errorMessage = "';' expected after 'endfor' keyword"; errorLevel = ERROR; errorStart = pos; errorEnd = pos; processParseExceptionDebug(e); } { final Statement[] stmtsArray = new Statement[list.size()]; list.toArray(stmtsArray); return new ForStatement(initializations, condition, increments, new Block(stmtsArray, stmtsArray[0].sourceStart, stmtsArray[stmtsArray.length-1].sourceEnd), token.sourceStart, pos);} ) } Expression[] ForInit() : { final Expression[] exprs; } { LOOKAHEAD(LocalVariableDeclaration()) exprs = LocalVariableDeclaration() {return exprs;} | exprs = StatementExpressionList() {return exprs;} } Expression[] StatementExpressionList() : { final ArrayList list = new ArrayList(); final Expression expr; } { expr = Expression() {list.add(expr);} ( Expression() {list.add(expr);})* { final Expression[] exprsArray = new Expression[list.size()]; list.toArray(exprsArray); return exprsArray; } } Continue ContinueStatement() : { Expression expr = null; final Token token; Token token2 = null; } { token = [ expr = Expression() ] try { token2 = } catch (ParseException e) { errorMessage = "';' expected after 'continue' statement"; errorLevel = ERROR; if (expr == null) { errorStart = token.sourceEnd+1; errorEnd = token.sourceEnd+1; } else { errorStart = expr.sourceEnd+1; errorEnd = expr.sourceEnd+1; } processParseExceptionDebug(e); } { if (token2 == null) { if (expr == null) { return new Continue(expr,token.sourceStart,token.sourceEnd); } return new Continue(expr,token.sourceStart,expr.sourceEnd); } return new Continue(expr,token.sourceStart,token2.sourceEnd); } } ReturnStatement ReturnStatement() : { Expression expr = null; final Token token; Token token2 = null; } { token = [ expr = Expression() ] try { token2 = } catch (ParseException e) { errorMessage = "';' expected after 'return' statement"; errorLevel = ERROR; if (expr == null) { errorStart = token.sourceEnd+1; errorEnd = token.sourceEnd+1; } else { errorStart = expr.sourceEnd+1; errorEnd = expr.sourceEnd+1; } processParseExceptionDebug(e); } { if (token2 == null) { if (expr == null) { return new ReturnStatement(expr,token.sourceStart,token.sourceEnd); } return new ReturnStatement(expr,token.sourceStart,expr.sourceEnd); } return new ReturnStatement(expr,token.sourceStart,token2.sourceEnd); } }