X-Git-Url: http://git.phpeclipse.com diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java index 6824bd6..8770f4a 100644 --- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/compiler/parser/Parser.java @@ -9,6 +9,7 @@ package net.sourceforge.phpdt.internal.compiler.parser; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.core.compiler.ITerminalSymbols; @@ -26,9 +27,11 @@ import net.sourceforge.phpeclipse.internal.compiler.ast.AND_AND_Expression; import net.sourceforge.phpeclipse.internal.compiler.ast.ASTNode; import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration; import net.sourceforge.phpeclipse.internal.compiler.ast.BinaryExpression; +import net.sourceforge.phpeclipse.internal.compiler.ast.Block; +import net.sourceforge.phpeclipse.internal.compiler.ast.BreakStatement; import net.sourceforge.phpeclipse.internal.compiler.ast.CompilationUnitDeclaration; import net.sourceforge.phpeclipse.internal.compiler.ast.ConditionalExpression; -import net.sourceforge.phpeclipse.internal.compiler.ast.EmptyStatement; +import net.sourceforge.phpeclipse.internal.compiler.ast.ContinueStatement; import net.sourceforge.phpeclipse.internal.compiler.ast.EqualExpression; import net.sourceforge.phpeclipse.internal.compiler.ast.Expression; import net.sourceforge.phpeclipse.internal.compiler.ast.FieldDeclaration; @@ -39,6 +42,7 @@ import net.sourceforge.phpeclipse.internal.compiler.ast.InstanceOfExpression; import net.sourceforge.phpeclipse.internal.compiler.ast.MethodDeclaration; import net.sourceforge.phpeclipse.internal.compiler.ast.OR_OR_Expression; import net.sourceforge.phpeclipse.internal.compiler.ast.OperatorIds; +import net.sourceforge.phpeclipse.internal.compiler.ast.ReturnStatement; import net.sourceforge.phpeclipse.internal.compiler.ast.SingleTypeReference; import net.sourceforge.phpeclipse.internal.compiler.ast.Statement; import net.sourceforge.phpeclipse.internal.compiler.ast.StringLiteral; @@ -190,8 +194,14 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI */ private void throwSyntaxError(String error) { int problemStartPosition = scanner.getCurrentTokenStartPosition(); - int problemEndPosition = scanner.getCurrentTokenEndPosition(); - throwSyntaxError(error, problemStartPosition, problemEndPosition + 1); + int problemEndPosition = scanner.getCurrentTokenEndPosition() + 1; + if (scanner.source.length <= problemEndPosition && problemEndPosition > 0) { + problemEndPosition = scanner.source.length - 1; + if (problemStartPosition > 0 && problemStartPosition >= problemEndPosition && problemEndPosition > 0) { + problemStartPosition = problemEndPosition - 1; + } + } + throwSyntaxError(error, problemStartPosition, problemEndPosition); } /** @@ -305,6 +315,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI */ public void parse(String s, HashMap variables) { fMethodVariables = variables; + fStackUnassigned = new ArrayList(); init(s); parse(); } @@ -351,30 +362,9 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI throwSyntaxError("End-of-file not reached."); } break; - } catch (SyntaxError sytaxErr1) { + } catch (SyntaxError syntaxError) { + // syntaxError.printStackTrace(); break; - // // if an error occured, - // // try to find keywords 'abstract' 'final' 'class' or 'function' - // // to parse the rest of the string - // boolean tokenize = scanner.tokenizeStrings; - // if (!tokenize) { - // scanner.tokenizeStrings = true; - // } - // try { - // while (token != TokenNameEOF) { - // if (token == TokenNameabstract || token == TokenNamefinal || token == TokenNameclass || token == TokenNamefunction) { - // break; - // } - // getNextToken(); - // } - // if (token == TokenNameEOF) { - // break; - // } - // } catch (SyntaxError sytaxErr2) { - // break; - // } finally { - // scanner.tokenizeStrings = tokenize; - // } } } while (true); @@ -412,10 +402,11 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } catch (SyntaxError sytaxErr1) { return; } finally { - int sourceEnd = scanner.getCurrentTokenStartPosition(); + int sourceEnd = methodDecl.sourceEnd; if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) { sourceEnd = methodDecl.declarationSourceStart + 1; } + methodDecl.sourceEnd = sourceEnd; methodDecl.declarationSourceEnd = sourceEnd; } } @@ -458,20 +449,27 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI return compilationUnit; } - private boolean isVariable() { - return token == TokenNameVariable; // || token == TokenNamethis; - } - - private void statementList() { + private Block statementList() { + boolean branchStatement = false; + Statement statement; + int blockStart = scanner.getCurrentTokenStartPosition(); + ArrayList blockStatements = new ArrayList(); do { try { - statement(TokenNameEOF); + statement = statement(); + blockStatements.add(statement); + if (branchStatement && statement != null) { + // reportSyntaxError("Unreachable code", statement.sourceStart, statement.sourceEnd); + problemReporter.unreachableCode(new String(scanner.getCurrentIdentifierSource()), statement.sourceStart, + statement.sourceEnd, referenceContext, compilationUnit.compilationResult); + } if ((token == TokenNameRBRACE) || (token == TokenNamecase) || (token == TokenNamedefault) || (token == TokenNameelse) || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor) || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch) || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) { - return; + return createBlock(blockStart, blockStatements); } + branchStatement = checkUnreachableStatements(statement); } catch (SyntaxError sytaxErr1) { // if an error occured, // try to find keywords @@ -486,7 +484,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI || (token == TokenNameelseif) || (token == TokenNameendif) || (token == TokenNameendfor) || (token == TokenNameendforeach) || (token == TokenNameendwhile) || (token == TokenNameendswitch) || (token == TokenNameenddeclare) || (token == TokenNameEOF) || (token == TokenNameERROR)) { - return; + return createBlock(blockStart, blockStatements); } if (token == TokenNameif || token == TokenNameswitch || token == TokenNamefor || token == TokenNamewhile || token == TokenNamedo || token == TokenNameforeach || token == TokenNamecontinue || token == TokenNamebreak @@ -510,29 +508,60 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } while (true); } + /** + * @param statement + * @return + */ + private boolean checkUnreachableStatements(Statement statement) { + if (statement instanceof ReturnStatement || statement instanceof ContinueStatement || statement instanceof BreakStatement) { + return true; + } else if (statement instanceof IfStatement && ((IfStatement) statement).checkUnreachable) { + return true; + } + return false; + } + + /** + * @param blockStart + * @param blockStatements + * @return + */ + private Block createBlock(int blockStart, ArrayList blockStatements) { + int blockEnd = scanner.getCurrentTokenEndPosition(); + Block b = Block.EmptyWith(blockStart, blockEnd); + b.statements = new Statement[blockStatements.size()]; + blockStatements.toArray(b.statements); + return b; + } + private void functionBody(MethodDeclaration methodDecl) { // '{' [statement-list] '}' if (token == TokenNameLBRACE) { getNextToken(); } else { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; throwSyntaxError("'{' expected in compound-statement."); } if (token != TokenNameRBRACE) { statementList(); } if (token == TokenNameRBRACE) { - // methodDecl.declarationSourceEnd = scanner.getCurrentTokenEndPosition(); + methodDecl.sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); } else { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; throwSyntaxError("'}' expected in compound-statement."); } } - private Statement statement(int previousToken) { + private Statement statement() { Statement statement = null; Expression expression; int sourceStart = scanner.getCurrentTokenStartPosition(); + int sourceEnd; if (token == TokenNameif) { + // T_IF '(' expr ')' statement elseif_list else_single + // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' getNextToken(); if (token == TokenNameLPAREN) { getNextToken(); @@ -545,8 +574,15 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } else { throwSyntaxError("')' expected after 'if' condition."); } - ifStatement(); - return new IfStatement(expression, statement, sourceStart, scanner.getCurrentTokenEndPosition()); + // create basic IfStatement + IfStatement ifStatement = new IfStatement(expression, null, null, sourceStart, -1); + if (token == TokenNameCOLON) { + getNextToken(); + ifStatementColon(ifStatement); + } else { + ifStatement(ifStatement); + } + return ifStatement; } else if (token == TokenNameswitch) { getNextToken(); if (token == TokenNameLPAREN) { @@ -629,7 +665,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI throwSyntaxError("'}' expected after 'do' keyword."); } } else { - statement(TokenNameEOF); + statement(); } if (token == TokenNamewhile) { getNextToken(); @@ -674,7 +710,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI foreach_optional_arg(); if (token == TokenNameEQUAL_GREATER) { getNextToken(); - variable(); + variable(false, false); } if (token == TokenNameRPAREN) { getNextToken(); @@ -683,20 +719,57 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } foreachStatement(); return statement; - } else if (token == TokenNamecontinue || token == TokenNamebreak || token == TokenNamereturn) { + } else if (token == TokenNamebreak) { + expression = null; getNextToken(); if (token != TokenNameSEMICOLON) { - expr(); + expression = expr(); } if (token == TokenNameSEMICOLON) { + sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); } else { if (token != TokenNameINLINE_HTML) { - throwSyntaxError("';' expected after 'continue', 'break' or 'return'."); + throwSyntaxError("';' expected after 'break'."); } + sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); } - return statement; + return new BreakStatement(null, sourceStart, sourceEnd); + } else if (token == TokenNamecontinue) { + expression = null; + getNextToken(); + if (token != TokenNameSEMICOLON) { + expression = expr(); + } + if (token == TokenNameSEMICOLON) { + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after 'continue'."); + } + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } + return new ContinueStatement(null, sourceStart, sourceEnd); + } else if (token == TokenNamereturn) { + expression = null; + getNextToken(); + if (token != TokenNameSEMICOLON) { + expression = expr(); + } + if (token == TokenNameSEMICOLON) { + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } else { + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("';' expected after 'return'."); + } + sourceEnd = scanner.getCurrentTokenEndPosition(); + getNextToken(); + } + return new ReturnStatement(expression, sourceStart, sourceEnd); } else if (token == TokenNameecho) { getNextToken(); expressionList(); @@ -710,7 +783,19 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } return statement; } else if (token == TokenNameINLINE_HTML) { - getNextToken(); + if (scanner.phpExpressionTag) { + // start of block + getNextToken(); + expr(); + if (token == TokenNameSEMICOLON) { + getNextToken(); + } + if (token != TokenNameINLINE_HTML) { + throwSyntaxError("Missing '?>' for open PHP expression block (' sourceEnd) { sourceEnd = methodDecl.declarationSourceStart + 1; } methodDecl.declarationSourceEnd = sourceEnd; + methodDecl.sourceEnd = sourceEnd; } return statement; } else if (token == TokenNamedeclare) { @@ -871,7 +957,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } else if (token == TokenNameLBRACE) { getNextToken(); if (token != TokenNameRBRACE) { - statementList(); + statement = statementList(); } if (token == TokenNameRBRACE) { getNextToken(); @@ -918,7 +1004,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameRPAREN); + statement(); } } @@ -978,7 +1064,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI if (token == TokenNameAND) { getNextToken(); } - w_variable(); + w_variable(true); } private void foreach_optional_arg() { @@ -994,8 +1080,9 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // global_var_list: // global_var_list ',' global_var //| global_var + HashSet set = peekVariableSet(); while (true) { - global_var(); + global_var(set); if (token != TokenNameCOMMA) { break; } @@ -1003,16 +1090,17 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } } - private void global_var() { + private void global_var(HashSet set) { //global_var: // T_VARIABLE //| '$' r_variable //| '$' '{' expr '}' if (token == TokenNameVariable) { - VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_GLOBAL_VAR); if (fMethodVariables != null) { + VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_GLOBAL_VAR); fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info); } + addVariableSet(set); getNextToken(); } else if (token == TokenNameDOLLAR) { getNextToken(); @@ -1034,13 +1122,15 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // static_var_list ',' T_VARIABLE //| static_var_list ',' T_VARIABLE '=' static_scalar //| T_VARIABLE - //| T_VARIABLE '=' static_scalar + //| T_VARIABLE '=' static_scalar, + HashSet set = peekVariableSet(); while (true) { if (token == TokenNameVariable) { - VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_STATIC_VAR); if (fMethodVariables != null) { + VariableInfo info = new VariableInfo(scanner.getCurrentTokenStartPosition(), VariableInfo.LEVEL_STATIC_VAR); fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info); } + addVariableSet(set); getNextToken(); if (token == TokenNameEQUAL) { getNextToken(); @@ -1063,7 +1153,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // unset_variable: // variable while (true) { - variable(); + variable(false, false); if (token != TokenNameCOMMA) { break; } @@ -1337,11 +1427,12 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI getNextToken(); functionDefinition(methodDecl); } finally { - int sourceEnd = scanner.getCurrentTokenStartPosition(); + int sourceEnd = methodDecl.sourceEnd; if (sourceEnd <= 0 || methodDecl.declarationSourceStart > sourceEnd) { sourceEnd = methodDecl.declarationSourceStart + 1; } methodDecl.declarationSourceEnd = sourceEnd; + methodDecl.sourceEnd = sourceEnd; } } else { if (!hasModifiers) { @@ -1526,15 +1617,23 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } } } - functionDeclarator(methodDecl); - if (token == TokenNameSEMICOLON) { - if (!isAbstract) { - throwSyntaxError("Body declaration expected for method: " + new String(methodDecl.selector)); + try { + pushFunctionVariableSet(); + functionDeclarator(methodDecl); + if (token == TokenNameSEMICOLON) { + if (!isAbstract) { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; + throwSyntaxError("Body declaration expected for method: " + new String(methodDecl.selector)); + } + getNextToken(); + return; + } + functionBody(methodDecl); + } finally { + if (!fStackUnassigned.isEmpty()) { + fStackUnassigned.remove(fStackUnassigned.size() - 1); } - getNextToken(); - return; } - functionBody(methodDecl); } private void functionDeclarator(MethodDeclaration methodDecl) { @@ -1554,12 +1653,14 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI if (token == TokenNameLPAREN) { getNextToken(); } else { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; throwSyntaxError("'(' expected in function declaration."); } if (token != TokenNameRPAREN) { parameter_list(methodDecl); } if (token != TokenNameRPAREN) { + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; throwSyntaxError("')' expected in function declaration."); } else { methodDecl.bodyStart = scanner.getCurrentTokenEndPosition() + 1; @@ -1567,6 +1668,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } } else { methodDecl.selector = "".toCharArray(); + methodDecl.sourceEnd = scanner.getCurrentTokenStartPosition() - 1; throwSyntaxError("Function name expected after keyword 'function'."); } } @@ -1591,6 +1693,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // static_scalar char[] typeIdentifier = null; if (token == TokenNameIdentifier || token == TokenNameVariable || token == TokenNameAND) { + HashSet set = peekVariableSet(); while (true) { if (token == TokenNameIdentifier) { typeIdentifier = scanner.getCurrentIdentifierSource(); @@ -1610,6 +1713,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI info.typeIdentifier = typeIdentifier; fMethodVariables.put(new String(scanner.getCurrentIdentifierSource()), info); } + addVariableSet(set); getNextToken(); if (token == TokenNameEQUAL) { getNextToken(); @@ -1711,162 +1815,270 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } while (token == TokenNamecase || token == TokenNamedefault); } - // public void labeledStatement() { - // if (token == TokenNamecase) { - // getNextToken(); - // constant(); - // if (token == TokenNameDDOT) { - // getNextToken(); - // statement(); - // } else { - // throwSyntaxError("':' character after 'case' constant expected."); - // } - // return; - // } else if (token == TokenNamedefault) { - // getNextToken(); - // if (token == TokenNameDDOT) { - // getNextToken(); - // statement(); - // } else { - // throwSyntaxError("':' character after 'default' expected."); - // } - // return; - // } - // } - // public void expressionStatement() { - // } - // private void inclusionStatement() { - // } - // public void compoundStatement() { - // } - // public void selectionStatement() { - // } - // - // public void iterationStatement() { - // } - // - // public void jumpStatement() { - // } - // - // public void outputStatement() { - // } - // - // public void scopeStatement() { - // } - // - // public void flowStatement() { - // } - // - // public void definitionStatement() { - // } - private void ifStatement() { - // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';' - if (token == TokenNameCOLON) { - getNextToken(); - if (token != TokenNameendif) { - statementList(); - switch (token) { - case TokenNameelse: - getNextToken(); - if (token == TokenNameCOLON) { - getNextToken(); - if (token != TokenNameendif) { - statementList(); - } - } else { - if (token == TokenNameif) { //'else if' - getNextToken(); - elseifStatementList(); - } else { - throwSyntaxError("':' expected after 'else'."); - } - } - break; - case TokenNameelseif: - getNextToken(); - elseifStatementList(); - break; + private void ifStatementColon(IfStatement iState) { + // T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' + HashSet assignedVariableSet = null; + try { + Block b = inner_statement_list(); + iState.thenStatement = b; + checkUnreachable(iState, b); + } finally { + assignedVariableSet = removeIfVariableSet(); + } + if (token == TokenNameelseif) { + try { + pushIfVariableSet(); + new_elseif_list(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null) { + assignedVariableSet.addAll(set); } } - if (token != TokenNameendif) { - throwSyntaxError("'endif' expected."); + } + try { + pushIfVariableSet(); + new_else_single(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null) { + HashSet topSet = peekVariableSet(); + if (topSet != null) { + topSet.addAll(set); + topSet.addAll(assignedVariableSet); + } } + } + if (token != TokenNameendif) { + throwSyntaxError("'endif' expected."); + } + getNextToken(); + if (token != TokenNameSEMICOLON) { + reportSyntaxError("';' expected after if-statement."); + iState.sourceEnd = scanner.getCurrentTokenStartPosition(); + } else { + iState.sourceEnd = scanner.getCurrentTokenEndPosition(); getNextToken(); - if (token != TokenNameSEMICOLON) { - throwSyntaxError("';' expected after if-statement."); + } + } + + private void ifStatement(IfStatement iState) { + // T_IF '(' expr ')' statement elseif_list else_single + HashSet assignedVariableSet = null; + try { + pushIfVariableSet(); + Statement s = statement(); + iState.thenStatement = s; + checkUnreachable(iState, s); + } finally { + assignedVariableSet = removeIfVariableSet(); + } + + if (token == TokenNameelseif) { + try { + pushIfVariableSet(); + elseif_list(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null) { + assignedVariableSet.addAll(set); + } + } + } + try { + pushIfVariableSet(); + else_single(iState); + } finally { + HashSet set = removeIfVariableSet(); + if (assignedVariableSet != null) { + HashSet topSet = peekVariableSet(); + if (topSet != null) { + topSet.addAll(set); + topSet.addAll(assignedVariableSet); + } } + } + } + + private void elseif_list(IfStatement iState) { + // /* empty */ + //| elseif_list T_ELSEIF '(' expr ')' statement + ArrayList conditionList = new ArrayList(); + ArrayList statementList = new ArrayList(); + Expression e; + Statement s; + while (token == TokenNameelseif) { getNextToken(); - } else { - // statement [else-statement] - statement(TokenNameEOF); - if (token == TokenNameelseif) { + if (token == TokenNameLPAREN) { getNextToken(); - if (token == TokenNameLPAREN) { - getNextToken(); - } else { - throwSyntaxError("'(' expected after 'elseif' keyword."); - } - expr(); - if (token == TokenNameRPAREN) { - getNextToken(); - } else { - throwSyntaxError("')' expected after 'elseif' condition."); - } - ifStatement(); - } else if (token == TokenNameelse) { + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + e = expr(); + conditionList.add(e); + if (token == TokenNameRPAREN) { getNextToken(); - statement(TokenNameEOF); + } else { + throwSyntaxError("')' expected after 'elseif' condition."); } + s = statement(); + statementList.add(s); + checkUnreachable(iState, s); } + iState.elseifConditions = new Expression[conditionList.size()]; + iState.elseifStatements = new Statement[statementList.size()]; + conditionList.toArray(iState.elseifConditions); + statementList.toArray(iState.elseifStatements); } - private void elseifStatementList() { - do { - elseifStatement(); - switch (token) { - case TokenNameelse: + private void new_elseif_list(IfStatement iState) { + // /* empty */ + //| new_elseif_list T_ELSEIF '(' expr ')' ':' inner_statement_list + ArrayList conditionList = new ArrayList(); + ArrayList statementList = new ArrayList(); + Expression e; + Block b; + while (token == TokenNameelseif) { + getNextToken(); + if (token == TokenNameLPAREN) { getNextToken(); - if (token == TokenNameCOLON) { - getNextToken(); - if (token != TokenNameendif) { - statementList(); - } - return; - } else { - if (token == TokenNameif) { //'else if' - getNextToken(); - } else { - throwSyntaxError("':' expected after 'else'."); - } - } - break; - case TokenNameelseif: + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + e = expr(); + conditionList.add(e); + if (token == TokenNameRPAREN) { getNextToken(); - break; - default: - return; + } else { + throwSyntaxError("')' expected after 'elseif' condition."); } - } while (true); + if (token == TokenNameCOLON) { + getNextToken(); + } else { + throwSyntaxError("':' expected after 'elseif' keyword."); + } + b = inner_statement_list(); + statementList.add(b); + checkUnreachable(iState, b); + } + iState.elseifConditions = new Expression[conditionList.size()]; + iState.elseifStatements = new Statement[statementList.size()]; + conditionList.toArray(iState.elseifConditions); + statementList.toArray(iState.elseifStatements); } - private void elseifStatement() { - if (token == TokenNameLPAREN) { + private void else_single(IfStatement iState) { + // /* empty */ + // T_ELSE statement + if (token == TokenNameelse) { getNextToken(); - expr(); - if (token != TokenNameRPAREN) { - throwSyntaxError("')' expected in else-if-statement."); - } + Statement s = statement(); + iState.elseStatement = s; + checkUnreachable(iState, s); + } else { + iState.checkUnreachable = false; + } + iState.sourceEnd = scanner.getCurrentTokenStartPosition(); + } + + private void new_else_single(IfStatement iState) { + // /* empty */ + //| T_ELSE ':' inner_statement_list + if (token == TokenNameelse) { getNextToken(); - if (token != TokenNameCOLON) { - throwSyntaxError("':' expected in else-if-statement."); + if (token == TokenNameCOLON) { + getNextToken(); + } else { + throwSyntaxError("':' expected after 'else' keyword."); } - getNextToken(); - if (token != TokenNameendif) { - statementList(); + Block b = inner_statement_list(); + iState.elseStatement = b; + checkUnreachable(iState, b); + } else { + iState.checkUnreachable = false; + } + } + + private Block inner_statement_list() { + // inner_statement_list inner_statement + // /* empty */ + return statementList(); + } + + /** + * @param iState + * @param b + */ + private void checkUnreachable(IfStatement iState, Statement s) { + if (s instanceof Block) { + Block b = (Block) s; + if (b.statements == null || b.statements.length == 0) { + iState.checkUnreachable = false; + } else { + int off = b.statements.length - 1; + if (!(b.statements[off] instanceof ReturnStatement) && !(b.statements[off] instanceof ContinueStatement) + && !(b.statements[off] instanceof BreakStatement)) { + if (!(b.statements[off] instanceof IfStatement) || !((IfStatement) b.statements[off]).checkUnreachable) { + iState.checkUnreachable = false; + } + } + } + } else { + if (!(s instanceof ReturnStatement) && !(s instanceof ContinueStatement) && !(s instanceof BreakStatement)) { + if (!(s instanceof IfStatement) || !((IfStatement) s).checkUnreachable) { + iState.checkUnreachable = false; + } } } } + // private void elseifStatementList() { + // do { + // elseifStatement(); + // switch (token) { + // case TokenNameelse: + // getNextToken(); + // if (token == TokenNameCOLON) { + // getNextToken(); + // if (token != TokenNameendif) { + // statementList(); + // } + // return; + // } else { + // if (token == TokenNameif) { //'else if' + // getNextToken(); + // } else { + // throwSyntaxError("':' expected after 'else'."); + // } + // } + // break; + // case TokenNameelseif: + // getNextToken(); + // break; + // default: + // return; + // } + // } while (true); + // } + + // private void elseifStatement() { + // if (token == TokenNameLPAREN) { + // getNextToken(); + // expr(); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected in else-if-statement."); + // } + // getNextToken(); + // if (token != TokenNameCOLON) { + // throwSyntaxError("':' expected in else-if-statement."); + // } + // getNextToken(); + // if (token != TokenNameendif) { + // statementList(); + // } + // } + // } + private void switchStatement() { if (token == TokenNameCOLON) { // ':' [labeled-statement-list] 'endswitch' ';' @@ -1909,7 +2121,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameEOF); + statement(); } } @@ -1927,7 +2139,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameEOF); + statement(); } } @@ -1944,7 +2156,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else { - statement(TokenNameEOF); + statement(); } } @@ -2064,7 +2276,30 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } switch (token) { case TokenNameisset: + // T_ISSET '(' isset_variables ')' + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected after keyword 'isset'"); + } + getNextToken(); + isset_variables(); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after keyword 'isset'"); + } + getNextToken(); + break; case TokenNameempty: + getNextToken(); + if (token != TokenNameLPAREN) { + throwSyntaxError("'(' expected after keyword 'empty'"); + } + getNextToken(); + variable(true, false); + if (token != TokenNameRPAREN) { + throwSyntaxError("')' expected after keyword 'empty'"); + } + getNextToken(); + break; case TokenNameeval: case TokenNameinclude: case TokenNameinclude_once: @@ -2283,9 +2518,28 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI case TokenNameVariable: case TokenNameDOLLAR: boolean rememberedVar = false; - Expression lhs = variable(); + Expression lhs = variable(true, true); + if (lhs != null && lhs instanceof FieldReference && token != TokenNameEQUAL && token != TokenNamePLUS_EQUAL + && token != TokenNameMINUS_EQUAL && token != TokenNameMULTIPLY_EQUAL && token != TokenNameDIVIDE_EQUAL + && token != TokenNameDOT_EQUAL && token != TokenNameREMAINDER_EQUAL && token != TokenNameAND_EQUAL + && token != TokenNameOR_EQUAL && token != TokenNameXOR_EQUAL && token != TokenNameRIGHT_SHIFT_EQUAL + && token != TokenNameLEFT_SHIFT_EQUAL) { + FieldReference ref = (FieldReference) lhs; + if (!containsVariableSet(ref.token)) { + problemReporter.uninitializedLocalVariable(new String(ref.token), ref.sourceStart(), ref.sourceEnd(), referenceContext, + compilationUnit.compilationResult); + addVariableSet(ref.token); + } + } + switch (token) { case TokenNameEQUAL: + if (lhs != null && lhs instanceof FieldReference) { + addVariableSet(((FieldReference) lhs).token); + } + // if (lhsVar != null) { + // addVariableSet(lhsVar); + // } getNextToken(); if (token == TokenNameAND) { getNextToken(); @@ -2309,7 +2563,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } } } else { - Expression rhs = variable(); + Expression rhs = variable(false, false); if (rhs != null && rhs instanceof FieldReference && lhs != null && lhs instanceof FieldReference) { // example: // $var = &$ref; @@ -2372,6 +2626,9 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI case TokenNameXOR_EQUAL: case TokenNameRIGHT_SHIFT_EQUAL: case TokenNameLEFT_SHIFT_EQUAL: + if (lhs != null && lhs instanceof FieldReference) { + addVariableSet(((FieldReference) lhs).token); + } getNextToken(); expr(); break; @@ -2394,6 +2651,9 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI getNextToken(); break; } else { + // System.out.println(scanner.getCurrentTokenStartPosition()); + // System.out.println(scanner.getCurrentTokenEndPosition()); + throwSyntaxError("Error in expression (found token '" + scanner.toStringAction(token) + "')."); } } @@ -2597,8 +2857,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // variable //| T_LIST '(' assignment_list ')' //| /* empty */ - if (token == TokenNameVariable || token == TokenNameDOLLAR) { - variable(); + if (token == TokenNameVariable) { + variable(true, false); + } else if (token == TokenNameDOLLAR) { + variable(false, false); } else { if (token == TokenNamelist) { getNextToken(); @@ -2639,17 +2901,17 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI while (true) { if (token == TokenNameAND) { getNextToken(); - variable(); + variable(true, false); } else { expr(); if (token == TokenNameAND) { getNextToken(); - variable(); + variable(true, false); } else if (token == TokenNameEQUAL_GREATER) { getNextToken(); if (token == TokenNameAND) { getNextToken(); - variable(); + variable(true, false); } else { expr(); } @@ -2675,7 +2937,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // } // } while (true); // } - private Expression variable_without_objects() { + private Expression variable_without_objects(boolean lefthandside, boolean ignoreVar) { // variable_without_objects: // reference_variable // | simple_indirect_reference reference_variable @@ -2685,10 +2947,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI while (token == TokenNameDOLLAR) { getNextToken(); } - return reference_variable(); + return reference_variable(lefthandside, ignoreVar); } - private Expression function_call() { + private Expression function_call(boolean lefthandside, boolean ignoreVar) { // function_call: // T_STRING '(' function_call_parameter_list ')' //| class_constant '(' function_call_parameter_list ')' @@ -2718,12 +2980,12 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI getNextToken(); } else { // static member: - variable_without_objects(); + variable_without_objects(true, false); } break; } } else { - ref = variable_without_objects(); + ref = variable_without_objects(lefthandside, ignoreVar); } if (token != TokenNameLPAREN) { if (defineName != null) { @@ -2794,7 +3056,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI while (true) { if (token == TokenNameAND) { getNextToken(); - w_variable(); + w_variable(true); } else { // if (token == TokenNameIdentifier || token == // TokenNameVariable @@ -2831,10 +3093,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI throwSyntaxError("'::' expected after class name (static_member)."); } getNextToken(); - variable_without_objects(); + variable_without_objects(false, false); } - private Expression base_variable_with_function_calls() { + private Expression base_variable_with_function_calls(boolean lefthandside, boolean ignoreVar) { // base_variable_with_function_calls: // base_variable //| function_call @@ -2856,7 +3118,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // scanner.phpMode = true; // } // if (functionCall) { - return function_call(); + return function_call(lefthandside, ignoreVar); // } else { // base_variable(); // } @@ -2877,7 +3139,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI while (token == TokenNameDOLLAR) { getNextToken(); } - reference_variable(); + reference_variable(false, false); } return ref; } @@ -2887,7 +3149,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI // // '$' // //| simple_indirect_reference '$' // } - private Expression reference_variable() { + private Expression reference_variable(boolean lefthandside, boolean ignoreVar) { // reference_variable: // reference_variable '[' dim_offset ']' // | reference_variable '{' expr '}' @@ -2896,7 +3158,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI if (Scanner.TRACE) { System.out.println("TRACE: reference_variable()"); } - ref = compound_variable(); + ref = compound_variable(lefthandside, ignoreVar); while (true) { if (token == TokenNameLBRACE) { ref = null; @@ -2907,6 +3169,10 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } getNextToken(); } else if (token == TokenNameLBRACKET) { + if (ref != null && ref instanceof FieldReference) { + FieldReference fref = (FieldReference) ref; + addVariableSet(fref.token); + } ref = null; getNextToken(); if (token != TokenNameRBRACKET) { @@ -2924,7 +3190,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI return ref; } - private Expression compound_variable() { + private Expression compound_variable(boolean lefthandside, boolean ignoreVar) { // compound_variable: // T_VARIABLE // | '$' '{' expr '}' @@ -2932,6 +3198,19 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI System.out.println("TRACE: compound_variable()"); } if (token == TokenNameVariable) { + if (!lefthandside) { + if (!containsVariableSet()) { + // reportSyntaxError("The local variable " + new String(scanner.getCurrentIdentifierSource()) + // + " may not have been initialized"); + problemReporter.uninitializedLocalVariable(new String(scanner.getCurrentIdentifierSource()), scanner + .getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition(), referenceContext, + compilationUnit.compilationResult); + } + } else { + if (!ignoreVar) { + addVariableSet(); + } + } FieldReference ref = new FieldReference(scanner.getCurrentIdentifierSource(), scanner.getCurrentTokenStartPosition()); getNextToken(); return ref; @@ -2952,11 +3231,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI getNextToken(); } return null; - } + } // private void dim_offset() { // // dim_offset: // // /* empty */ - // private void dim_offset() { - // // dim_offset: - // // /* empty */ // // | expr // expr(); // } @@ -2968,7 +3244,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI System.out.println("TRACE: object_property()"); } if (token == TokenNameVariable || token == TokenNameDOLLAR) { - variable_without_objects(); + variable_without_objects(false, false); } else { object_dim_list(); } @@ -3034,23 +3310,23 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } private void r_variable() { - variable(); + variable(false, false); } - private void w_variable() { - variable(); + private void w_variable(boolean lefthandside) { + variable(lefthandside, false); } private void rw_variable() { - variable(); + variable(false, false); } - private Expression variable() { + private Expression variable(boolean lefthandside, boolean ignoreVar) { // variable: // base_variable_with_function_calls T_OBJECT_OPERATOR // object_property method_or_not variable_properties // | base_variable_with_function_calls - Expression ref = base_variable_with_function_calls(); + Expression ref = base_variable_with_function_calls(lefthandside, ignoreVar); if (token == TokenNameMINUS_GREATER) { ref = null; getNextToken(); @@ -3369,32 +3645,32 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI private void internal_functions_in_yacc() { // int start = 0; switch (token) { - case TokenNameisset: - // T_ISSET '(' isset_variables ')' - getNextToken(); - if (token != TokenNameLPAREN) { - throwSyntaxError("'(' expected after keyword 'isset'"); - } - getNextToken(); - isset_variables(); - if (token != TokenNameRPAREN) { - throwSyntaxError("')' expected after keyword 'isset'"); - } - getNextToken(); - break; - case TokenNameempty: - // T_EMPTY '(' variable ')' - getNextToken(); - if (token != TokenNameLPAREN) { - throwSyntaxError("'(' expected after keyword 'empty'"); - } - getNextToken(); - variable(); - if (token != TokenNameRPAREN) { - throwSyntaxError("')' expected after keyword 'empty'"); - } - getNextToken(); - break; + // case TokenNameisset: + // // T_ISSET '(' isset_variables ')' + // getNextToken(); + // if (token != TokenNameLPAREN) { + // throwSyntaxError("'(' expected after keyword 'isset'"); + // } + // getNextToken(); + // isset_variables(); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected after keyword 'isset'"); + // } + // getNextToken(); + // break; + // case TokenNameempty: + // // T_EMPTY '(' variable ')' + // getNextToken(); + // if (token != TokenNameLPAREN) { + // throwSyntaxError("'(' expected after keyword 'empty'"); + // } + // getNextToken(); + // variable(false); + // if (token != TokenNameRPAREN) { + // throwSyntaxError("')' expected after keyword 'empty'"); + // } + // getNextToken(); + // break; case TokenNameinclude: //T_INCLUDE expr checkFileName(token); @@ -3521,7 +3797,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI throwSyntaxError("Variable expected after keyword 'isset'"); } while (true) { - variable(); + variable(true, false); if (token == TokenNameCOMMA) { getNextToken(); } else { @@ -3839,6 +4115,8 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI HashMap fMethodVariables = null; + ArrayList fStackUnassigned = new ArrayList(); + //ast stack final static int AstStackIncrement = 100; @@ -4206,8 +4484,7 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI } } if (scanner.recordLineSeparator) { - // compilationUnit.compilationResult.lineSeparatorPositions = - // scanner.getLineEnds(); + compilationUnit.compilationResult.lineSeparatorPositions = scanner.getLineEnds(); } // check placement anomalies against other kinds of brackets for (int kind = 0; kind < BracketKinds; kind++) { @@ -4343,4 +4620,123 @@ public class Parser implements ITerminalSymbols, CompilerModifiers, ParserBasicI //endPosition is just before the ; } + + public final static String[] GLOBALS = { + "$this", + "$_COOKIE", + "$_ENV", + "$_FILES", + "$_GET", + "$GLOBALS", + "$_POST", + "$_REQUEST", + "$_SESSION", + "$_SERVER" }; + + /** + * + */ + private void pushFunctionVariableSet() { + HashSet set = new HashSet(); + if (fStackUnassigned.isEmpty()) { + for (int i = 0; i < GLOBALS.length; i++) { + set.add(GLOBALS[i]); + } + } + fStackUnassigned.add(set); + } + + private void pushIfVariableSet() { + if (!fStackUnassigned.isEmpty()) { + HashSet set = new HashSet(); + fStackUnassigned.add(set); + } + } + + private HashSet removeIfVariableSet() { + if (!fStackUnassigned.isEmpty()) { + return (HashSet) fStackUnassigned.remove(fStackUnassigned.size() - 1); + } + return null; + } + + /** + * Returns the set of assigned variables returns null if no Set is defined at the current scanner position + */ + private HashSet peekVariableSet() { + if (!fStackUnassigned.isEmpty()) { + return (HashSet) fStackUnassigned.get(fStackUnassigned.size() - 1); + } + return null; + } + + /** + * add the current identifier source to the set of assigned variables + * + * @param set + */ + private void addVariableSet(HashSet set) { + if (set != null) { + set.add(new String(scanner.getCurrentTokenSource())); + } + } + + /** + * add the current identifier source to the set of assigned variables + * + */ + private void addVariableSet() { + HashSet set = peekVariableSet(); + if (set != null) { + set.add(new String(scanner.getCurrentTokenSource())); + } + } + + /** + * add the current identifier source to the set of assigned variables + * + */ + private void addVariableSet(char[] token) { + HashSet set = peekVariableSet(); + if (set != null) { + set.add(new String(token)); + } + } + + /** + * check if the current identifier source is in the set of assigned variables Returns true, if no set is defined for the + * current scanner position + * + */ + private boolean containsVariableSet() { + return containsVariableSet(scanner.getCurrentTokenSource()); + // if (!fStackUnassigned.isEmpty()) { + // HashSet set; + // String str = new String(scanner.getCurrentTokenSource()); + // for (int i = 0; i < fStackUnassigned.size(); i++) { + // set = (HashSet) fStackUnassigned.get(i); + // if (set.contains(str)) { + // return true; + // } + // } + // return false; + // } + // return true; + } + + private boolean containsVariableSet(char[] token) { + + if (!fStackUnassigned.isEmpty()) { + HashSet set; + String str = new String(token); + for (int i = 0; i < fStackUnassigned.size(); i++) { + set = (HashSet) fStackUnassigned.get(i); + if (set.contains(str)) { + return true; + } + } + return false; + } + return true; + } } \ No newline at end of file