From: khartlage Date: Tue, 10 Dec 2002 21:20:42 +0000 (+0000) Subject: improved/refactored php syntax parser X-Git-Url: http://git.phpeclipse.com?hp=dc9e7d2fc4245a64183c7529f5dfa3d3cd6239e2 improved/refactored php syntax parser --- diff --git a/net.sourceforge.phpeclipse/src/junit/sourceforge/phpeclipse/PHPParserTestCase.java b/net.sourceforge.phpeclipse/src/junit/sourceforge/phpeclipse/PHPParserTestCase.java index 7770048..5675731 100644 --- a/net.sourceforge.phpeclipse/src/junit/sourceforge/phpeclipse/PHPParserTestCase.java +++ b/net.sourceforge.phpeclipse/src/junit/sourceforge/phpeclipse/PHPParserTestCase.java @@ -11,7 +11,7 @@ import org.eclipse.core.runtime.CoreException; import junit.framework.TestCase; -import net.sourceforge.phpeclipse.phpeditor.PHPParser; +import net.sourceforge.phpeclipse.phpeditor.phpparser.PHPParser; /** * Tests the php parser @@ -34,6 +34,15 @@ public class PHPParserTestCase extends TestCase { checkHTML(" foo "); checkHTML(" "); + checkPHP("($a==\"b\") || (c($this->x)==\"d\");"); + checkPHP("(substr($this->file, 0, 2) == \"MM\");"); + checkPHP("(substr($this->file, 0, 2) == \"MM\") || substr($this->file, 0, 2) == \"II\";"); + checkPHP("return (substr($this->file, 0, 2) == \"MM\") || substr($this->file, 0, 2) == \"II\";"); + checkPHP("$this->highlightfile->linkscripts{$category}"); + checkPHP("$code = call_user_method($this->highlightfile->linkscripts{$category}, $this->highlightfile, $oldword, $this->output_module)"); + checkPHP("$this->startmap[$startcurrtag]();"); + checkPHP("new $this->startmap[$startcurrtag]();"); + checkPHP("$this->highlightfile = new $this->startmap[$startcurrtag]();"); checkPHP("echo \"Test\", \"me\";"); checkPHP("print (\"Test me\");"); checkPHP("$s = << eol) { + ch = str.charAt(eol++); + if (ch == '\n') { + eol--; + break; + } + } + throw new SyntaxError(rowCount, chIndx - columnCount + 1, str.substring(columnCount, eol), error); + } + + private void throwSyntaxError(String error, int startRow) { + + throw new SyntaxError(startRow, 0, " ", error); + } + + /** + * Method Declaration. + * + *@see + */ + private void getChar() { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + + return; + } + + chIndx = str.length() + 1; + ch = ' '; + // token = TT_EOF; + phpEnd = true; + } + + private void getNextToken_OldVersion() throws CoreException { + phpEnd = false; + + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + token = TT_UNDEFINED; + if (ch == '\n') { + rowCount++; + columnCount = chIndx; + continue; // while loop + } + if (str.length() == chIndx) { + phpEnd = true; + } + if (!Character.isWhitespace(ch)) { + if (ch == '$') { + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '{') { + chIndx++; + token = TT_DOLLAROPEN; + return; + } + } + getIdentifier(); + return; + } + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) { + getIdentifier(); + return; + } + if (ch >= '0' && ch <= '9') { + getNumber(); + return; + } + if (ch == '/') { + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '/') { + chIndx++; + // read comment until end of line: + while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) { + chIndx++; + } + continue; + } else if (str.charAt(chIndx) == '*') { + chIndx++; + // multi line comment: + while (str.length() > chIndx) { + if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') { + chIndx += 2; + break; + } + ch = str.charAt(chIndx++); + if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + continue; + } + } + } else if (ch == '#') { + // read comment until end of line: + while ((str.length() > chIndx) && (str.charAt(chIndx) != '\n')) { + chIndx++; + } + continue; + } else if (ch == '"') { + // read string until end + boolean openString = true; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\\') { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + } + } else if (ch == '"') { + openString = false; + break; + } else if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + if (openString) { + throwSyntaxError("Open string character '\"' at end of file."); + } + token = TT_INTERPOLATED_STRING; + return; + } else if (ch == '\'') { + // read string until end + boolean openString = true; + int startRow = rowCount; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\\') { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + } + } else if (ch == '\'') { + openString = false; + break; + } else if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + if (openString) { + throwSyntaxError("Open string character \"'\" at end of file.", startRow); + } + token = TT_STRING_CONSTANT; + return; + } else if (ch == '`') { + // read string until end + boolean openString = true; + int startRow = rowCount; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\\') { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + } + } else if (ch == '`') { + openString = false; + break; + } else if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + if (openString) { + throwSyntaxError("Open string character \"`\" at end of file.", startRow); + } + setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO); + token = TT_STRING_CONSTANT; + return; + } + + switch (ch) { + + case '(' : + token = TT_ARGOPEN; + + break; + case ')' : + token = TT_ARGCLOSE; + + break; + case '{' : + token = TT_LISTOPEN; + + break; + case '}' : + token = TT_LISTCLOSE; + + break; + case '[' : + token = TT_PARTOPEN; + + break; + case ']' : + token = TT_PARTCLOSE; + + break; + case ',' : + token = TT_COMMA; + + break; + case '?' : + token = TT_QUESTIONMARK; + break; + case '@' : + token = TT_AT; + break; + case '~' : + token = TT_TILDE; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_TILDEASSIGN; + + break; + } + } + break; + case '.' : + token = TT_DOT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_DOTASSIGN; + + break; + } + } + + break; + case '"' : + token = TT_STRING; + + break; + case '%' : + token = TT_MOD; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_MODASSIGN; + + break; + } + } + break; + case ';' : + token = TT_SEMICOLON; + + break; + case '^' : + token = TT_POW; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_POWASSIGN; + + break; + } + } + break; + case '/' : + token = TT_DIV; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_DIVIDEBY; + + break; + } + } + + break; + case '*' : + token = TT_MULTIPLY; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '*') { + chIndx++; + token = TT_POW; + + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_TIMESBY; + + break; + } + } + + break; + case '+' : + token = TT_ADD; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '+') { + chIndx++; + token = TT_INCREMENT; + + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_ADDTO; + + break; + } + } + break; + case '-' : + token = TT_SUBTRACT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '-') { + chIndx++; + token = TT_DECREMENT; + + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_SUBTRACTFROM; + + break; + } + if (str.charAt(chIndx) == '>') { + chIndx++; + token = TT_REF; + + break; + } + } + + break; + case '=' : + token = TT_ASSIGN; + + if (str.length() > chIndx) { + ch = str.charAt(chIndx); + + if (ch == '=') { + chIndx++; + token = TT_EQUAL; + if (str.length() > chIndx) { + ch = str.charAt(chIndx); + + if (ch == '=') { + chIndx++; + token = TT_EX_EQUAL; + } + } + break; + } + if (ch == '>') { + chIndx++; + token = TT_FOREACH; + + break; + } + } + + break; + case '!' : + token = TT_NOT; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_UNEQUAL; + if (str.length() > chIndx) { + ch = str.charAt(chIndx); + + if (ch == '=') { + chIndx++; + token = TT_EX_UNEQUAL; + } + } + break; + } + } + + break; + case '>' : + token = TT_GREATER; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_GREATEREQUAL; + break; + } + if (str.charAt(chIndx) == '>') { + chIndx++; + token = TT_RSHIFT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_RSHIFTASSIGN; + break; + } + } + break; + } + } + + break; + case '<' : + token = TT_LESS; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_LESSEQUAL; + + break; + } + if (str.charAt(chIndx) == '<') { + chIndx++; + token = TT_LSHIFT; + if (str.charAt(chIndx) == '<') { + // heredoc + int startRow = rowCount; + if (str.length() > chIndx) { + + ch = str.charAt(++chIndx); + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) { + chIndx++; + getIdentifier(); + token = TT_STRING_CONSTANT; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\n') { + if (str.length() >= chIndx + identifier.length()) { + if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) { + chIndx += identifier.length(); + return; + } + } + } + } + } + } + throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow); + } else if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_LSHIFTASSIGN; + break; + } + break; + } + } + + break; + + case '|' : + token = TT_LINE; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '|') { + chIndx++; + token = TT_OR; + + break; + } + } + + break; + case '&' : + token = TT_AMPERSAND; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '&') { + chIndx++; + token = TT_AND; + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_ANDASSIGN; + break; + } + break; + } + + break; + case ':' : + token = TT_DDOT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == ':') { + chIndx++; + token = TT_DDOT2; + } + } + break; + case '#' : + token = TT_HASH; + + break; + // case '@' : + // token = TT_AT; + // + // break; + default : + throwSyntaxError("unexpected character: '" + ch + "'"); + } + + if (token == TT_UNDEFINED) { + throwSyntaxError("token not found"); + } + + return; + } + } + + chIndx = str.length() + 1; + ch = ' '; + token = TT_EOF; + phpEnd = true; + PHPString temp; + if (phpList != null) { + if (currentPHPString < phpList.size()) { + token = TT_UNDEFINED; + temp = (PHPString) phpList.get(currentPHPString++); + this.str = temp.getPHPString(); + this.token = TT_EOF; + this.chIndx = 0; + this.rowCount = temp.getLineNumber(); + this.columnCount = 0; + getNextToken(); + phpEnd = true; + } else { + token = TT_UNDEFINED; + return; + } + } + } + /** + * gets the next token from input + */ + private void getNextToken() throws CoreException { + boolean phpFound = false; + char ch2; + + phpEnd = false; + try { + if (!phpMode) { + + while (str.length() > chIndx) { + token = TT_UNDEFINED; + ch = str.charAt(chIndx++); + + if (ch == '\n') { + rowCount++; + } + if (ch == '<') { + ch2 = str.charAt(chIndx++); + if (ch2 == '?') { + ch2 = str.charAt(chIndx++); + if (Character.isWhitespace(ch2)) { + // php start + phpMode = true; + phpFound = true; + break; + } else if (ch2 == 'p') { + ch2 = str.charAt(chIndx++); + if (ch2 == 'h') { + ch2 = str.charAt(chIndx++); + if (ch2 == 'p') { + phpMode = true; + phpFound = true; + break; + } + chIndx--; + } + chIndx--; + } else if (ch2 == 'P') { + ch2 = str.charAt(chIndx++); + if (ch2 == 'H') { + ch2 = str.charAt(chIndx++); + if (ch2 == 'P') { + phpMode = true; + phpFound = true; + break; + } + chIndx--; + } + chIndx--; + } + chIndx--; + } + chIndx--; + } + } + + } + + if (phpMode) { + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + token = TT_UNDEFINED; + if (ch == '\n') { + rowCount++; + columnCount = chIndx; + continue; // while loop + } + if (str.length() == chIndx) { + phpEnd = true; + } + if (!Character.isWhitespace(ch)) { + if (ch == '$') { + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '{') { + chIndx++; + token = TT_DOLLAROPEN; + return; + } + } + getIdentifier(); + return; + } + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$')) { + getIdentifier(); + return; + } + if (ch >= '0' && ch <= '9') { + getNumber(); + return; + } + if (ch == '/') { + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '/') { + ch = '/'; + chIndx++; + // read comment until end of line: + while ((str.length() > chIndx) && (ch != '\n')) { + ch = str.charAt(chIndx++); + if (ch == '?') { + ch2 = str.charAt(chIndx); + if (ch2 == '>') { + chIndx++; + token = TT_HTML; + // php end + phpMode = false; + phpEnd = true; + return; + } + } + } + rowCount++; + continue; + + } else if (str.charAt(chIndx) == '*') { + chIndx++; + // multi line comment: + while (str.length() > chIndx) { + if (str.charAt(chIndx) == '*' && (str.length() > (chIndx + 1)) && str.charAt(chIndx + 1) == '/') { + chIndx += 2; + break; + } + ch = str.charAt(chIndx++); + if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + continue; + } + } + } else if (ch == '#') { + // read comment until end of line: + while ((str.length() > chIndx) && (ch != '\n')) { + ch = str.charAt(chIndx++); + if (ch == '?') { + ch2 = str.charAt(chIndx); + if (ch2 == '>') { + chIndx++; + token = TT_HTML; + // php end + phpMode = false; + phpEnd = true; + return; + } + } + } + rowCount++; + continue; + + } else if (ch == '"') { + // read string until end + boolean openString = true; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\\') { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + } + } else if (ch == '"') { + openString = false; + break; + } else if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + if (openString) { + throwSyntaxError("Open string character '\"' at end of file."); + } + token = TT_INTERPOLATED_STRING; + return; + } else if (ch == '\'') { + // read string until end + boolean openString = true; + int startRow = rowCount; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\\') { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + } + } else if (ch == '\'') { + openString = false; + break; + } else if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + if (openString) { + throwSyntaxError("Open string character \"'\" at end of file.", startRow); + } + token = TT_STRING_CONSTANT; + return; + } else if (ch == '`') { + // read string until end + boolean openString = true; + int startRow = rowCount; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\\') { + if (str.length() > chIndx) { + ch = str.charAt(chIndx++); + } + } else if (ch == '`') { + openString = false; + break; + } else if (ch == '\n') { + rowCount++; + columnCount = chIndx; + } + } + if (openString) { + throwSyntaxError("Open string character \"`\" at end of file.", startRow); + } + setMarker("Other string delimiters prefered (found \"`\").", rowCount, PHPParser.INFO); + token = TT_STRING_CONSTANT; + return; + } + + switch (ch) { + + case '(' : + token = TT_ARGOPEN; + + break; + case ')' : + token = TT_ARGCLOSE; + + break; + case '{' : + token = TT_LISTOPEN; + + break; + case '}' : + token = TT_LISTCLOSE; + + break; + case '[' : + token = TT_PARTOPEN; + + break; + case ']' : + token = TT_PARTCLOSE; + + break; + case ',' : + token = TT_COMMA; + + break; + case '?' : + token = TT_QUESTIONMARK; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '>') { + chIndx++; + token = TT_HTML; + // php end + phpMode = false; + phpEnd = true; + break; + } + } + + break; + case '@' : + token = TT_AT; + break; + case '~' : + token = TT_TILDE; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_TILDEASSIGN; + + break; + } + } + break; + case '.' : + token = TT_DOT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_DOTASSIGN; + + break; + } + } + + break; + case '"' : + token = TT_STRING; + + break; + case '%' : + token = TT_MOD; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_MODASSIGN; + + break; + } + } + break; + case ';' : + token = TT_SEMICOLON; + + break; + case '^' : + token = TT_POW; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_POWASSIGN; + + break; + } + } + break; + case '/' : + token = TT_DIV; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_DIVIDEBY; + + break; + } + } + + break; + case '*' : + token = TT_MULTIPLY; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '*') { + chIndx++; + token = TT_POW; + + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_TIMESBY; + + break; + } + } + + break; + case '+' : + token = TT_ADD; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '+') { + chIndx++; + token = TT_INCREMENT; + + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_ADDTO; + + break; + } + } + break; + case '-' : + token = TT_SUBTRACT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '-') { + chIndx++; + token = TT_DECREMENT; + + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_SUBTRACTFROM; + + break; + } + if (str.charAt(chIndx) == '>') { + chIndx++; + token = TT_REF; + + break; + } + } + + break; + case '=' : + token = TT_ASSIGN; + + if (str.length() > chIndx) { + ch = str.charAt(chIndx); + + if (ch == '=') { + chIndx++; + token = TT_EQUAL; + if (str.length() > chIndx) { + ch = str.charAt(chIndx); + + if (ch == '=') { + chIndx++; + token = TT_EX_EQUAL; + } + } + break; + } + if (ch == '>') { + chIndx++; + token = TT_FOREACH; + + break; + } + } + + break; + case '!' : + token = TT_NOT; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_UNEQUAL; + if (str.length() > chIndx) { + ch = str.charAt(chIndx); + + if (ch == '=') { + chIndx++; + token = TT_EX_UNEQUAL; + } + } + break; + } + } + + break; + case '>' : + token = TT_GREATER; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_GREATEREQUAL; + break; + } + if (str.charAt(chIndx) == '>') { + chIndx++; + token = TT_RSHIFT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_RSHIFTASSIGN; + break; + } + } + break; + } + } + + break; + case '<' : + token = TT_LESS; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_LESSEQUAL; + + break; + } + if (str.charAt(chIndx) == '<') { + chIndx++; + token = TT_LSHIFT; + if (str.charAt(chIndx) == '<') { + // heredoc + int startRow = rowCount; + if (str.length() > chIndx) { + + ch = str.charAt(++chIndx); + if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_')) { + chIndx++; + getIdentifier(); + token = TT_STRING_CONSTANT; + while (str.length() > chIndx) { + ch = str.charAt(chIndx++); + if (ch == '\n') { + if (str.length() >= chIndx + identifier.length()) { + if (str.substring(chIndx, chIndx + identifier.length()).equals(identifier)) { + chIndx += identifier.length(); + return; + } + } + } + } + } + } + throwSyntaxError("Open heredoc syntax after operator '<<<'.", startRow); + } else if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_LSHIFTASSIGN; + break; + } + break; + } + } + + break; + + case '|' : + token = TT_LINE; + + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '|') { + chIndx++; + token = TT_OR; + + break; + } + } + + break; + case '&' : + token = TT_AMPERSAND; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == '&') { + chIndx++; + token = TT_AND; + break; + } + if (str.charAt(chIndx) == '=') { + chIndx++; + token = TT_ANDASSIGN; + break; + } + break; + } + + break; + case ':' : + token = TT_DDOT; + if (str.length() > chIndx) { + if (str.charAt(chIndx) == ':') { + chIndx++; + token = TT_DDOT2; + } + } + break; + case '#' : + token = TT_HASH; + + break; + // case '@' : + // token = TT_AT; + // + // break; + default : + throwSyntaxError("unexpected character: '" + ch + "'"); + } + + if (token == TT_UNDEFINED) { + throwSyntaxError("token not found"); + } + + return; + } + } + } + } catch (StringIndexOutOfBoundsException e) { + // catched from charAt + } + + chIndx = str.length() + 1; + ch = ' '; + token = TT_EOF; + phpEnd = true; + //PHPString temp; + // if (phpList != null) { + // if (currentPHPString < phpList.size()) { + // token = TT_UNDEFINED; + // temp = (PHPString) phpList.get(currentPHPString++); + // this.str = temp.getPHPString(); + // this.token = TT_EOF; + // this.chIndx = 0; + // this.rowCount = temp.getLineNumber(); + // this.columnCount = 0; + // getNextToken(); + // phpEnd = true; + // } else { + // token = TT_UNDEFINED; + // return; + // } + // } + } + + private void getIdentifier() { + StringBuffer ident = new StringBuffer(); + + ident.append(ch); + if (ch == '$') { + token = TT_VARIABLE; + } else { + token = TT_IDENTIFIER; + } + getChar(); + while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '_')) { + ident.append(ch); + getChar(); + } + identifier = ident.toString(); + chIndx--; + + Integer i = (Integer) keywordMap.get(identifier.toLowerCase()); + if (i != null) { + token = i.intValue(); + } + } + + private void getNumber() { + StringBuffer inum = new StringBuffer(); + char dFlag = ' '; + int numFormat = 10; + + // save first digit + char firstCh = ch; + inum.append(ch); + + getChar(); + // determine number conversions: + if (firstCh == '0') { + switch (ch) { + case 'b' : + numFormat = 2; + getChar(); + break; + case 'B' : + numFormat = 2; + getChar(); + break; + case 'o' : + numFormat = 8; + getChar(); + break; + case 'O' : + numFormat = 8; + getChar(); + break; + case 'x' : + numFormat = 16; + getChar(); + break; + case 'X' : + numFormat = 16; + getChar(); + break; + } + } + + if (numFormat == 16) { + while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) { + inum.append(ch); + getChar(); + } + } else { + while ((ch >= '0' && ch <= '9') || (ch == '.') || (ch == 'E') || (ch == 'e')) { + if ((ch == '.') || (ch == 'E') || (ch == 'e')) { + if (ch == '.' && dFlag != ' ') { + break; + } + if ((dFlag == 'E') || (dFlag == 'e')) { + break; + } + dFlag = ch; + inum.append(ch); + getChar(); + if ((ch == '-') || (ch == '+')) { + inum.append(ch); + getChar(); + } + } else { + inum.append(ch); + getChar(); + } + } + } + chIndx--; + + try { + if (dFlag != ' ') { + doubleNumber = new Double(inum.toString()); + token = TT_DOUBLE_NUMBER; + return; + } else { + longNumber = Long.valueOf(inum.toString(), numFormat); + token = TT_INT_NUMBER; + return; + } + + } catch (Throwable e) { + throwSyntaxError("Number format error: " + inum.toString()); + } + } + + public void htmlParserTester(String input) { + int lineNumber = 1; + int startLineNumber = 1; + int startIndex = 0; + char ch; + char ch2; + boolean phpMode = false; + boolean phpFound = false; + + phpList = new ArrayList(); + currentPHPString = 0; + + try { + int i = 0; + while (i < input.length()) { + ch = input.charAt(i++); + if (ch == '\n') { + lineNumber++; + } + if ((!phpMode) && ch == '<') { + ch2 = input.charAt(i++); + if (ch2 == '?') { + ch2 = input.charAt(i++); + if (Character.isWhitespace(ch2)) { + // php start + phpMode = true; + phpFound = true; + startIndex = i; + startLineNumber = lineNumber; + continue; + } else if (ch2 == 'p') { + ch2 = input.charAt(i++); + if (ch2 == 'h') { + ch2 = input.charAt(i++); + if (ch2 == 'p') { + phpMode = true; + phpFound = true; + startIndex = i; + startLineNumber = lineNumber; + continue; + } + i--; + } + i--; + } else if (ch2 == 'P') { + ch2 = input.charAt(i++); + if (ch2 == 'H') { + ch2 = input.charAt(i++); + if (ch2 == 'P') { + phpMode = true; + phpFound = true; + startIndex = i; + startLineNumber = lineNumber; + continue; + } + i--; + } + i--; + } + i--; + } + i--; + } + + if (phpMode) { + if (ch == '/' && i < input.length()) { + ch2 = input.charAt(i++); + if (ch2 == '/') { + while (i < input.length()) { + ch = input.charAt(i++); + if (ch == '?' && i < input.length()) { + ch2 = input.charAt(i++); + if (ch2 == '>') { + // php end + phpMode = false; + phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber)); + continue; + } + i--; + } else if (ch == '\n') { + lineNumber++; + break; + } + } + continue; + } else if (ch2 == '*') { + // multi-line comment + while (i < input.length()) { + ch = input.charAt(i++); + if (ch == '\n') { + lineNumber++; + } else if (ch == '*' && i < input.length()) { + ch2 = input.charAt(i++); + if (ch2 == '/') { + break; + } + i--; + } + } + continue; + } else { + i--; + } + } else if (ch == '#') { + while (i < input.length()) { + ch = input.charAt(i++); + if (ch == '?' && i < input.length()) { + ch2 = input.charAt(i++); + if (ch2 == '>') { + // php end + phpMode = false; + phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber)); + continue; + } + i--; + } else if (ch == '\n') { + lineNumber++; + break; + } + } + continue; + } else if (ch == '"') { + ch = ' '; + while (i < input.length()) { + ch = input.charAt(i++); + if (ch == '\n') { + lineNumber++; + } else if (ch == '\\' && i < input.length()) { // escape + i++; + } else if (ch == '"') { + break; + } + } + continue; + } else if (ch == '\'') { + ch = ' '; + while (i < input.length()) { + ch = input.charAt(i++); + if (ch == '\n') { + lineNumber++; + } else if (ch == '\\' && i < input.length()) { // escape + i++; + } else if (ch == '\'') { + break; + } + } + continue; + } + + if (ch == '?' && i < input.length()) { + ch2 = input.charAt(i++); + if (ch2 == '>') { + // php end + phpMode = false; + phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber)); + continue; + } + i--; + } + } + } + + if (!phpFound) { + setMarker("No PHP source code found.", lineNumber, PHPParser.INFO); + } else { + if (phpMode) { + setMarker("Open PHP tag at end of file.", lineNumber, PHPParser.INFO); + phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber)); + } + // for (int j=0;j"); + // } + phpParserTester(null, 1); + // PHPString temp; + // for(int j=0;j TT_KEYWORD && token != TT_list && token != TT_new) { + String keyword = identifier; + if (token == TT_include || token == TT_include_once) { + getNextToken(); + expression(); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' character after 'include' or 'include_once' expected."); + } + getNextToken(); + } + return; + } else if (token == TT_require || token == TT_require_once) { + getNextToken(); + //constant(); + expression(); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' character after 'require' or 'require_once' expected."); + } + getNextToken(); + } + return; + } else if (token == TT_if) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'if' keyword."); + } + expression(); + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'if' condition."); + } + ifStatement(); + return; + + } else if (token == TT_switch) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'switch' keyword."); + } + expression(); + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'switch' condition."); + } + switchStatement(); + return; + } else if (token == TT_for) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'for' keyword."); + } + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + expressionList(); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + throwSyntaxError("';' expected after 'for'."); + } + } + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + expressionList(); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + throwSyntaxError("';' expected after 'for'."); + } + } + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + expressionList(); + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'for'."); + } + } + forStatement(); + return; + } else if (token == TT_while) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'while' keyword."); + } + expression(); + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'while' condition."); + } + whileStatement(); + return; + } else if (token == TT_do) { + getNextToken(); + if (token == TT_LISTOPEN) { + getNextToken(); + } else { + throwSyntaxError("'{' expected after 'do' keyword."); + } + if (token != TT_LISTCLOSE) { + statementList(); + } + if (token == TT_LISTCLOSE) { + getNextToken(); + } else { + throwSyntaxError("'}' expected after 'do' keyword."); + } + if (token == TT_while) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'while' keyword."); + } + expression(); + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'while' condition."); + } + } else { + throwSyntaxError("'while' expected after 'do' keyword."); + } + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' expected after do-while statement."); + } + getNextToken(); + } + return; + } else if (token == TT_foreach) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'foreach' keyword."); + } + expression(); + if (token == TT_as) { + getNextToken(); + } else { + throwSyntaxError("'as' expected after 'foreach' exxpression."); + } + variable(); + if (token == TT_FOREACH) { + getNextToken(); + variable(); + } + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'foreach' expression."); + } + foreachStatement(); + return; + + } else if (token == TT_continue || token == TT_break || token == TT_return) { + getNextToken(); + if (token != TT_SEMICOLON) { + expression(); + } + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' expected after 'continue', 'break' or 'return'."); + } + getNextToken(); + } + return; + + } else if (token == TT_echo) { + getNextToken(); + expressionList(); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' expected after 'echo' statement."); + } + getNextToken(); + } + return; + // } else if (token == TT_print) { + // getNextToken(); + // expression(); + // if (token == TT_SEMICOLON) { + // getNextToken(); + // } else { + // if (!phpEnd) { + // throwSyntaxError("';' expected after 'print' statement."); + // } + // getNextToken(); + // } + // return; + + } else if (token == TT_global || token == TT_static) { + getNextToken(); + variableList(); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' expected after 'global' or 'static' statement."); + } + getNextToken(); + } + return; + + // } else if (token == TT_unset) { + // getNextToken(); + // if (token == TT_ARGOPEN) { + // getNextToken(); + // } else { + // throwSyntaxError("'(' expected after 'unset' keyword."); + // } + // variableList(); + // if (token == TT_ARGCLOSE) { + // getNextToken(); + // } else { + // throwSyntaxError("')' expected after 'unset' statement."); + // } + // if (token == TT_SEMICOLON) { + // getNextToken(); + // } else { + // if (!phpEnd) { + // throwSyntaxError("';' expected after 'unset' statement."); + // } + // getNextToken(); + // } + // return; + + // } else if (token == TT_exit || token == TT_die) { + // getNextToken(); + // if (token != TT_SEMICOLON) { + // exitStatus(); + // } + // if (token == TT_SEMICOLON) { + // getNextToken(); + // } else { + // if (!phpEnd) { + // throwSyntaxError("';' expected after 'exit' or 'die' statement."); + // } + // getNextToken(); + // } + // return; + + } else if (token == TT_define) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'define' keyword."); + } + expression(); + if (token == TT_COMMA) { + getNextToken(); + } else { + throwSyntaxError("',' expected after first 'define' constant."); + } + expression(); + if (token == TT_COMMA) { + getNextToken(); + expression(); + } + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'define' statement."); + } + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + if (!phpEnd) { + throwSyntaxError("';' expected after 'define' statement."); + } + getNextToken(); + } + return; + } else if (token == TT_function) { + getNextToken(); + functionDefinition(); + return; + } else if (token == TT_class) { + getNextToken(); + classDeclarator(); + classBody(); + return; + // } else { + // throwSyntaxError("Unexpected keyword '" + keyword + "'"); + } else if (token == TT_LISTOPEN) { + // compoundStatement + getNextToken(); + if (token != TT_LISTCLOSE) { + statementList(); + } + if (token == TT_LISTCLOSE) { + getNextToken(); + return; + } else { + throwSyntaxError("'}' expected."); + } + } else { + if (token != TT_SEMICOLON) { + expression(); + } + if (token == TT_SEMICOLON) { + getNextToken(); + return; + } else { + if (!phpEnd) { + throwSyntaxError("';' expected after expression."); + } + getNextToken(); + } + } + } + + private void classDeclarator() throws CoreException { + //identifier + //identifier 'extends' identifier + if (token == TT_IDENTIFIER) { + getNextToken(); + if (token == TT_extends) { + getNextToken(); + if (token == TT_IDENTIFIER) { + getNextToken(); + } else { + throwSyntaxError("Class name expected after keyword 'extends'."); + } + } + } else { + throwSyntaxError("Class name expected after keyword 'class'."); + } + } + + private void classBody() throws CoreException { + //'{' [class-element-list] '}' + if (token == TT_LISTOPEN) { + getNextToken(); + if (token != TT_LISTCLOSE) { + classElementList(); + } + if (token == TT_LISTCLOSE) { + getNextToken(); + } else { + throwSyntaxError("'}' expected at end of class body."); + } + } else { + throwSyntaxError("'{' expected at start of class body."); + } + } + + private void classElementList() throws CoreException { + do { + classElement(); + } while (token == TT_function || token == TT_var); + } + + private void classElement() throws CoreException { + //class-property + //function-definition + if (token == TT_function) { + getNextToken(); + functionDefinition(); + } else if (token == TT_var) { + getNextToken(); + classProperty(); + } else { + throwSyntaxError("'function' or 'var' expected."); + } + } + + private void classProperty() throws CoreException { + //'var' variable ';' + //'var' variable '=' constant ';' + do { + if (token == TT_VARIABLE) { + getNextToken(); + if (token == TT_ASSIGN) { + getNextToken(); + constant(); + } + } else { + throwSyntaxError("Variable expected after keyword 'var'."); + } + if (token != TT_COMMA) { + break; + } + getNextToken(); + } while (true); + if (token == TT_SEMICOLON) { + getNextToken(); + } else { + throwSyntaxError("';' expected after variable declaration."); + } + } + + private void functionDefinition() throws CoreException { + functionDeclarator(); + compoundStatement(); + } + + private void functionDeclarator() throws CoreException { + //identifier '(' [parameter-list] ')' + if (token == TT_AMPERSAND) { + getNextToken(); + } + if (token == TT_IDENTIFIER) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected in function declaration."); + } + if (token != TT_ARGCLOSE) { + parameterList(); + } + if (token != TT_ARGCLOSE) { + throwSyntaxError("')' expected in function declaration."); + } else { + getNextToken(); + } + } + } + // + private void parameterList() throws CoreException { + //parameter-declaration + //parameter-list ',' parameter-declaration + do { + parameterDeclaration(); + if (token != TT_COMMA) { + break; + } + getNextToken(); + } while (true); + } + + private void parameterDeclaration() throws CoreException { + //variable + //variable-reference + if (token == TT_AMPERSAND) { + getNextToken(); + if (token == TT_VARIABLE) { + getNextToken(); + } else { + throwSyntaxError("Variable expected after reference operator '&'."); + } + } + //variable '=' constant + if (token == TT_VARIABLE) { + getNextToken(); + if (token == TT_ASSIGN) { + getNextToken(); + constant(); + } + return; + } + } + + private void labeledStatementList() throws CoreException { + if (token != TT_case && token != TT_default) { + throwSyntaxError("'case' or 'default' expected."); + } + do { + if (token == TT_case) { + getNextToken(); + constant(); + if (token == TT_DDOT) { + getNextToken(); + if (token == TT_case || token == TT_default) { // empty case statement ? + continue; + } + statementList(); + } else if (token == TT_SEMICOLON) { + setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO); + getNextToken(); + if (token == TT_case) { // empty case statement ? + continue; + } + statementList(); + } else { + throwSyntaxError("':' character after 'case' constant expected."); + } + } else { // TT_default + getNextToken(); + if (token == TT_DDOT) { + getNextToken(); + statementList(); + } else { + throwSyntaxError("':' character after 'default' expected."); + } + } + } while (token == TT_case || token == TT_default); + } + + // public void labeledStatement() { + // if (token == TT_case) { + // getNextToken(); + // constant(); + // if (token == TT_DDOT) { + // getNextToken(); + // statement(); + // } else { + // throwSyntaxError("':' character after 'case' constant expected."); + // } + // return; + // } else if (token == TT_default) { + // getNextToken(); + // if (token == TT_DDOT) { + // 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() throws CoreException { + // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';' + if (token == TT_DDOT) { + getNextToken(); + statementList(); + switch (token) { + case TT_else : + getNextToken(); + if (token == TT_DDOT) { + getNextToken(); + statementList(); + } else { + if (token == TT_if) { //'else if' + getNextToken(); + elseifStatementList(); + } else { + throwSyntaxError("':' expected after 'else'."); + } + } + break; + case TT_elseif : + getNextToken(); + elseifStatementList(); + break; + } + + if (token != TT_endif) { + throwSyntaxError("'endif' expected."); + } + getNextToken(); + if (token != TT_SEMICOLON) { + throwSyntaxError("';' expected after if-statement."); + } + getNextToken(); + } else { + // statement [else-statement] + statement(); + if (token == TT_elseif) { + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected after 'elseif' keyword."); + } + expression(); + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'elseif' condition."); + } + ifStatement(); + } else if (token == TT_else) { + getNextToken(); + statement(); + } + } + } + + private void elseifStatementList() throws CoreException { + do { + elseifStatement(); + switch (token) { + case TT_else : + getNextToken(); + if (token == TT_DDOT) { + getNextToken(); + statementList(); + return; + } else { + if (token == TT_if) { //'else if' + getNextToken(); + } else { + throwSyntaxError("':' expected after 'else'."); + } + } + break; + case TT_elseif : + getNextToken(); + break; + default : + return; + } + } while (true); + } + + private void elseifStatement() throws CoreException { + if (token == TT_ARGOPEN) { + getNextToken(); + expression(); + if (token != TT_ARGOPEN) { + throwSyntaxError("')' expected in else-if-statement."); + } + getNextToken(); + if (token != TT_DDOT) { + throwSyntaxError("':' expected in else-if-statement."); + } + getNextToken(); + statementList(); + } + } + + private void switchStatement() throws CoreException { + if (token == TT_DDOT) { + // ':' [labeled-statement-list] 'endswitch' ';' + getNextToken(); + labeledStatementList(); + if (token != TT_endswitch) { + throwSyntaxError("'endswitch' expected."); + } + getNextToken(); + if (token != TT_SEMICOLON) { + throwSyntaxError("';' expected after switch-statement."); + } + getNextToken(); + } else { + // '{' [labeled-statement-list] '}' + if (token != TT_LISTOPEN) { + throwSyntaxError("'{' expected in switch statement."); + } + getNextToken(); + if (token != TT_LISTCLOSE) { + labeledStatementList(); + } + if (token != TT_LISTCLOSE) { + throwSyntaxError("'}' expected in switch statement."); + } + getNextToken(); + + } + } + + private void forStatement() throws CoreException { + if (token == TT_DDOT) { + getNextToken(); + statementList(); + if (token != TT_endfor) { + throwSyntaxError("'endfor' expected."); + } + getNextToken(); + if (token != TT_SEMICOLON) { + throwSyntaxError("';' expected after for-statement."); + } + getNextToken(); + } else { + statement(); + } + } + + private void whileStatement() throws CoreException { + // ':' statement-list 'endwhile' ';' + if (token == TT_DDOT) { + getNextToken(); + statementList(); + if (token != TT_endwhile) { + throwSyntaxError("'endwhile' expected."); + } + getNextToken(); + if (token != TT_SEMICOLON) { + throwSyntaxError("';' expected after while-statement."); + } + getNextToken(); + } else { + statement(); + } + } + + private void foreachStatement() throws CoreException { + if (token == TT_DDOT) { + getNextToken(); + statementList(); + if (token != TT_endforeach) { + throwSyntaxError("'endforeach' expected."); + } + getNextToken(); + if (token != TT_SEMICOLON) { + throwSyntaxError("';' expected after foreach-statement."); + } + getNextToken(); + } else { + statement(); + } + } + + private void exitStatus() throws CoreException { + if (token == TT_ARGOPEN) { + getNextToken(); + } else { + throwSyntaxError("'(' expected in 'exit-status'."); + } + if (token != TT_ARGCLOSE) { + expression(); + } + if (token == TT_ARGCLOSE) { + getNextToken(); + } else { + throwSyntaxError("')' expected after 'exit-status'."); + } + } + + private void expressionList() throws CoreException { + do { + expression(); + if (token == TT_COMMA) { + getNextToken(); + } else { + break; + } + } while (true); + } + + private void expression() throws CoreException { + // if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) { + // getNextToken(); + // } else { + logicalinclusiveorExpression(); + // while (token != TT_SEMICOLON) { + // getNextToken(); + // // } + // } + } + + private void postfixExpression() throws CoreException { + String ident; + boolean castFlag = false; + switch (token) { + case TT_new : + getNextToken(); + expression(); + break; + case TT_null : + getNextToken(); + break; + case TT_false : + getNextToken(); + break; + case TT_true : + getNextToken(); + break; + case TT_STRING_CONSTANT : + getNextToken(); + break; + case TT_INTERPOLATED_STRING : + getNextToken(); + break; + case TT_ARGOPEN : + getNextToken(); + if (token == TT_IDENTIFIER) { + // check if identifier is a type: + ident = identifier; + String str = identifier.toLowerCase(); + for (int i = 0; i < PHP_TYPES.length; i++) { + if (PHP_TYPES[i].equals(str)) { + castFlag = true; + break; + } + } + if (castFlag) { + getNextToken(); + if (token != TT_ARGCLOSE) { + throwSyntaxError(") expected after cast-type '" + ident + "'."); + } + getNextToken(); + expression(); + break; + } + } + if (!castFlag) { + expression(); + } + if (token != TT_ARGCLOSE) { + throwSyntaxError(") expected in postfix-expression."); + } + getNextToken(); + break; + case TT_DOUBLE_NUMBER : + getNextToken(); + break; + case TT_INT_NUMBER : + getNextToken(); + break; + case TT_DOLLAROPEN : + getNextToken(); + expression(); + if (token != TT_LISTCLOSE) { + throwSyntaxError("'}' expected after indirect variable token '${'."); + } + getNextToken(); + break; + case TT_VARIABLE : + ident = identifier; + getNextToken(); + if (token == TT_LISTOPEN) { + getNextToken(); + expression(); + if (token != TT_LISTCLOSE) { + throwSyntaxError("'}' expected after variable '" + ident + "' in variable-expression."); + } + getNextToken(); + } else if (token == TT_ARGOPEN) { + getNextToken(); + if (token != TT_ARGCLOSE) { + expressionList(); + if (token != TT_ARGCLOSE) { + throwSyntaxError("')' expected after variable '" + ident + "' in postfix-expression."); + } + } + getNextToken(); + } + break; + case TT_IDENTIFIER : + ident = identifier; + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + if (token != TT_ARGCLOSE) { + expressionList(); + if (token != TT_ARGCLOSE) { + throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression."); + } + } + getNextToken(); + } + break; + case TT_print : + getNextToken(); + expression(); + // if (token == TT_SEMICOLON) { + // getNextToken(); + // } else { + // if (!phpEnd) { + // throwSyntaxError("';' expected after 'print' statement."); + // } + // getNextToken(); + // } + break; + case TT_list : + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + if (token == TT_COMMA) { + getNextToken(); + } + expressionList(); + if (token != TT_ARGCLOSE) { + throwSyntaxError("')' expected after 'list' keyword."); + } + getNextToken(); + // if (token == TT_SET) { + // getNextToken(); + // logicalinclusiveorExpression(); + // } + } else { + throwSyntaxError("'(' expected after 'list' keyword."); + } + break; + // case TT_exit : + // getNextToken(); + // if (token != TT_SEMICOLON) { + // exitStatus(); + // } + // if (token == TT_SEMICOLON) { + // getNextToken(); + // } else { + // if (!phpEnd) { + // throwSyntaxError("';' expected after 'exit' expression."); + // } + // getNextToken(); + // } + // break; + // case TT_die : + // getNextToken(); + // if (token != TT_SEMICOLON) { + // exitStatus(); + // } + // if (token == TT_SEMICOLON) { + // getNextToken(); + // } else { + // if (!phpEnd) { + // throwSyntaxError("';' expected after 'die' expression."); + // } + // } + // break; + + // case TT_array : + // getNextToken(); + // if (token == TT_ARGOPEN) { + // getNextToken(); + // if (token == TT_COMMA) { + // getNextToken(); + // } + // expressionList(); + // if (token != TT_ARGCLOSE) { + // throwSyntaxError("')' expected after 'list' keyword."); + // } + // getNextToken(); + // if (token == TT_SET) { + // getNextToken(); + // logicalinclusiveorExpression(); + // } + // } else { + // throwSyntaxError("'(' expected after 'list' keyword."); + // } + // break; + } + boolean while_flag = true; + do { + switch (token) { + case TT_PARTOPEN : + getNextToken(); + expression(); + if (token != TT_PARTCLOSE) { + throwSyntaxError("] expected in postfix-expression."); + } + getNextToken(); + break; + case TT_DDOT2 : // :: + case TT_REF : // -> + getNextToken(); + if (token > TT_KEYWORD) { + ident = identifier; + setMarker("Avoid using keyword '" + ident + "' as variable name.", rowCount, PHPParser.INFO); + } + switch (token) { + case TT_VARIABLE : + ident = identifier; + getNextToken(); + // if (token == TT_ARGOPEN) { + // getNextToken(); + // expressionList(); + // if (token != TT_ARGCLOSE) { + // throwSyntaxError(") expected after variable '" + ident + "'."); + // } + // getNextToken(); + // } + break; + case TT_IDENTIFIER : + ident = identifier; + getNextToken(); + break; + case TT_LISTOPEN : + getNextToken(); + expression(); + if (token != TT_LISTCLOSE) { + throwSyntaxError("} expected in postfix-expression."); + } + getNextToken(); + break; + default : + throwSyntaxError("Syntax error after '->' token."); + } while (token == TT_PARTOPEN || token == TT_ARGOPEN || token == TT_LISTOPEN) { + if (token == TT_PARTOPEN) { + getNextToken(); + expressionList(); + if (token != TT_PARTCLOSE) { + throwSyntaxError("] expected after '->'."); + } + getNextToken(); + } + if (token == TT_ARGOPEN) { + getNextToken(); + expressionList(); + if (token != TT_ARGCLOSE) { + throwSyntaxError(") expected after '->'."); + } + getNextToken(); + } + if (token == TT_LISTOPEN) { + getNextToken(); + expression(); + if (token != TT_LISTCLOSE) { + throwSyntaxError("} expected after '->'."); + } + getNextToken(); + } + } + break; + case TT_INCREMENT : + getNextToken(); + break; + case TT_DECREMENT : + getNextToken(); + break; + default : + while_flag = false; + } + + } + while (while_flag); + } + + private void unaryExpression() throws CoreException { + switch (token) { + case TT_INCREMENT : + getNextToken(); + unaryExpression(); + break; + case TT_DECREMENT : + getNextToken(); + unaryExpression(); + break; + // '@' '&' '*' '+' '-' '~' '!' + case TT_AT : + getNextToken(); + castExpression(); + break; + case TT_AMPERSAND : + getNextToken(); + castExpression(); + break; + case TT_MULTIPLY : + getNextToken(); + castExpression(); + break; + case TT_ADD : + getNextToken(); + castExpression(); + break; + case TT_SUBTRACT : + getNextToken(); + castExpression(); + break; + case TT_TILDE : + getNextToken(); + castExpression(); + break; + case TT_NOT : + getNextToken(); + castExpression(); + break; + default : + postfixExpression(); + } + } + + private void castExpression() throws CoreException { + // if (token == TT_ARGOPEN) { + // getNextToken(); + // typeName(); + // if (token != TT_ARGCLOSE) { + // throwSyntaxError(") expected after cast-expression."); + // } + // getNextToken(); + // } + unaryExpression(); + } + + private void typeName() throws CoreException { + //'string' 'unset' 'array' 'object' + //'bool' 'boolean' + //'real' 'double' 'float' + //'int' 'integer' + String ident = ""; + if (token == TT_IDENTIFIER) { + ident = identifier; + String str = identifier.toLowerCase(); + getNextToken(); + for (int i = 0; i < PHP_TYPES.length; i++) { + if (PHP_TYPES[i].equals(str)) { + return; + } + } + } + throwSyntaxError("Expected type cast '( )'; Got '" + ident + "'."); + } + + private void assignExpression() throws CoreException { + castExpression(); + if (token == TT_ASSIGN) { // = + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_DOTASSIGN) { // .= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_FOREACH) { // => + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_ADDTO) { // += + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_SUBTRACTFROM) { // -= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_TIMESBY) { // *= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_DIVIDEBY) { // *= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_MODASSIGN) { // %= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_ANDASSIGN) { // &= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_POWASSIGN) { // ^= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_LSHIFTASSIGN) { // <<= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_RSHIFTASSIGN) { // >>= + getNextToken(); + logicalinclusiveorExpression(); + } else if (token == TT_TILDEASSIGN) { // ~= + getNextToken(); + logicalinclusiveorExpression(); + } + } + + private void multiplicativeExpression() throws CoreException { + do { + assignExpression(); + if (token != TT_MULTIPLY && token != TT_DIV && token != TT_MOD) { + return; + } + getNextToken(); + } while (true); + } + + private void concatenationExpression() throws CoreException { + do { + multiplicativeExpression(); + if (token != TT_DOT) { + return; + } + getNextToken(); + } while (true); + } + + private void additiveExpression() throws CoreException { + do { + concatenationExpression(); + if (token != TT_ADD && token != TT_SUBTRACT) { + return; + } + getNextToken(); + } while (true); + } + + private void shiftExpression() throws CoreException { + do { + additiveExpression(); + if (token != TT_LSHIFT && token != TT_RSHIFT) { + return; + } + getNextToken(); + } while (true); + } + + private void relationalExpression() throws CoreException { + do { + shiftExpression(); + if (token != TT_LESS && token != TT_GREATER && token != TT_LESSEQUAL && token != TT_GREATEREQUAL) { + return; + } + getNextToken(); + } while (true); + } + + private void identicalExpression() throws CoreException { + do { + relationalExpression(); + if (token != TT_EX_EQUAL && token != TT_EX_UNEQUAL) { + return; + } + getNextToken(); + } while (true); + } + + private void equalityExpression() throws CoreException { + do { + identicalExpression(); + if (token != TT_EQUAL && token != TT_UNEQUAL) { + return; + } + getNextToken(); + } while (true); + } + + private void ternaryExpression() throws CoreException { + equalityExpression(); + if (token == TT_QUESTIONMARK) { + getNextToken(); + expression(); + if (token == TT_DDOT) { + getNextToken(); + expression(); + } else { + throwSyntaxError("':' expected in ternary operator '? :'."); + } + } + } + + private void andExpression() throws CoreException { + do { + ternaryExpression(); + if (token != TT_AMPERSAND) { + return; + } + getNextToken(); + } while (true); + } + + private void exclusiveorExpression() throws CoreException { + do { + andExpression(); + if (token != TT_POW) { + return; + } + getNextToken(); + } while (true); + } + + private void inclusiveorExpression() throws CoreException { + do { + exclusiveorExpression(); + if (token != TT_LINE) { + return; + } + getNextToken(); + } while (true); + } + + private void booleanandExpression() throws CoreException { + do { + inclusiveorExpression(); + if (token != TT_AND) { + return; + } + getNextToken(); + } while (true); + } + + private void booleanorExpression() throws CoreException { + do { + booleanandExpression(); + if (token != TT_OR) { + return; + } + getNextToken(); + } while (true); + } + + private void logicalandExpression() throws CoreException { + do { + booleanorExpression(); + if (token != TT_and) { + return; + } + getNextToken(); + } while (true); + } + + private void logicalexclusiveorExpression() throws CoreException { + do { + logicalandExpression(); + if (token != TT_xor) { + return; + } + getNextToken(); + } while (true); + } + + private void logicalinclusiveorExpression() throws CoreException { + do { + logicalexclusiveorExpression(); + if (token != TT_or) { + return; + } + getNextToken(); + } while (true); + } + + // public void assignmentExpression() { + // if (token == TT_VARIABLE) { + // getNextToken(); + // if (token == TT_SET) { + // getNextToken(); + // logicalinclusiveorExpression(); + // } + // } else { + // logicalinclusiveorExpression(); + // } + // } + + private void variableList() throws CoreException { + do { + variable(); + if (token == TT_COMMA) { + getNextToken(); + } else { + break; + } + } while (true); + } + + private void variable() throws CoreException { + if (token == TT_DOLLAROPEN) { + getNextToken(); + expression(); + ; + if (token != TT_LISTCLOSE) { + throwSyntaxError("'}' expected after indirect variable token '${'."); + } + getNextToken(); + } else { + if (token == TT_VARIABLE) { + getNextToken(); + if (token == TT_PARTOPEN) { + getNextToken(); + expression(); + if (token != TT_PARTCLOSE) { + throwSyntaxError("']' expected in variable-list."); + } + getNextToken(); + } else if (token == TT_ASSIGN) { + getNextToken(); + constant(); + } + } else { + throwSyntaxError("$-variable expected in variable-list."); + } + } + } + + private void constant() throws CoreException { + String ident; + switch (token) { + case TT_ADD : + getNextToken(); + switch (token) { + case TT_DOUBLE_NUMBER : + getNextToken(); + break; + case TT_INT_NUMBER : + getNextToken(); + break; + default : + throwSyntaxError("Constant expected after '+' presign."); + } + break; + case TT_SUBTRACT : + getNextToken(); + switch (token) { + case TT_DOUBLE_NUMBER : + getNextToken(); + break; + case TT_INT_NUMBER : + getNextToken(); + break; + default : + throwSyntaxError("Constant expected after '-' presign."); + } + break; + case TT_null : + getNextToken(); + break; + case TT_false : + getNextToken(); + break; + case TT_true : + getNextToken(); + break; + case TT_IDENTIFIER : + ident = identifier; + getNextToken(); + if (token == TT_ARGOPEN) { + getNextToken(); + if (token != TT_ARGCLOSE) { + expressionList(); + if (token != TT_ARGCLOSE) { + throwSyntaxError("')' expected after identifier '" + ident + "' in postfix-expression."); + } + } + getNextToken(); + } + break; + case TT_STRING_CONSTANT : + getNextToken(); + break; + case TT_INTERPOLATED_STRING : + getNextToken(); + break; + case TT_DOUBLE_NUMBER : + getNextToken(); + break; + case TT_INT_NUMBER : + getNextToken(); + break; + default : + throwSyntaxError("Constant expected."); + } + } + + /** + * Call the php parse command ( php -l -f <filename> ) + * and create markers according to the external parser output + */ + public static void phpExternalParse(IFile file) { + //IFile file = (IFile) resource; + IPath path = file.getFullPath(); + IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore(); + String filename = file.getLocation().toString(); + + String[] arguments = { filename }; + MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.EXTERNAL_PARSER_PREF)); + String command = form.format(arguments); + + String parserResult = PHPStartApacheAction.execute(command, "External parser: "); + + try { + // parse the buffer to find the errors and warnings + createMarkers(parserResult, file); + } catch (CoreException e) { + } + } + + /** + * Create markers according to the external parser output + */ + private static void createMarkers(String output, IFile file) throws CoreException { + // delete all markers + file.deleteMarkers(IMarker.PROBLEM, false, 0); + + int indx = 0; + int brIndx = 0; + boolean flag = true; + while ((brIndx = output.indexOf("
", indx)) != -1) { + // newer php error output (tested with 4.2.3) + scanLine(output, file, indx, brIndx); + indx = brIndx + 6; + flag = false; + } + if (flag) { + while ((brIndx = output.indexOf("
", indx)) != -1) { + // older php error output (tested with 4.2.3) + scanLine(output, file, indx, brIndx); + indx = brIndx + 4; + } + } + } + + private static void scanLine(String output, IFile file, int indx, int brIndx) throws CoreException { + String current; + String outLineNumberString; + StringBuffer lineNumberBuffer = new StringBuffer(10); + char ch; + current = output.substring(indx, brIndx); + + if (current.indexOf(PARSE_WARNING_STRING) != -1 || current.indexOf(PARSE_ERROR_STRING) != -1) { + int onLine = current.indexOf("on line "); + if (onLine != -1) { + lineNumberBuffer.delete(0, lineNumberBuffer.length()); + for (int i = onLine; i < current.length(); i++) { + ch = current.charAt(i); + if ('0' <= ch && '9' >= ch) { + lineNumberBuffer.append(ch); + } + } + + int lineNumber = Integer.parseInt(lineNumberBuffer.toString()); + + Hashtable attributes = new Hashtable(); + + current = current.replaceAll("\n", ""); + current = current.replaceAll("", ""); + current = current.replaceAll("", ""); + MarkerUtilities.setMessage(attributes, current); + + if (current.indexOf(PARSE_ERROR_STRING) != -1) + attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR)); + else if (current.indexOf(PARSE_WARNING_STRING) != -1) + attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING)); + else + attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO)); + MarkerUtilities.setLineNumber(attributes, lineNumber); + MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM); + } + } + } +} \ No newline at end of file diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/phpparser/SyntaxError.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/phpparser/SyntaxError.java new file mode 100644 index 0000000..5da81e8 --- /dev/null +++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/phpparser/SyntaxError.java @@ -0,0 +1,65 @@ +/* + * SyntaxError.java + * Copyright (C) 2000 Klaus Hartlage + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +package net.sourceforge.phpeclipse.phpeditor.phpparser; + +/** + * Exception for a syntax error detected by the HartMath parser + * + */ +public class SyntaxError extends Error { + + int lineNumber; + int columnNumber; + String currentLine; + String error; + /** + * SyntaxError exception + * + * + * @see + */ + public SyntaxError(int lineNumber, int columnNumber, String currentLine, String error) { + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.currentLine = currentLine; + this.error = error; + } + + public String getMessage() { + // StringBuffer buf = new StringBuffer(256); + // buf.append("Syntax error in line:"); + // buf.append(lineNumber+1); + // buf.append(": "+ error + "\n"); + // buf.append( currentLine + "\n"); + // for (int i=0; i<(columnNumber-1); i++) { + // buf.append(' '); + // } + // buf.append('^'); + // return buf.toString(); + + + // System.err.println(currentLine); + //System.err.println(columnNumber); + return error; + } + + public int getLine() { + return lineNumber; + } +}