improved php parser
authorkhartlage <khartlage>
Sun, 24 Nov 2002 14:49:22 +0000 (14:49 +0000)
committerkhartlage <khartlage>
Sun, 24 Nov 2002 14:49:22 +0000 (14:49 +0000)
net.sourceforge.phpeclipse/src/junit/sourceforge/phpeclipse/PHPParserTestCase.java
net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParser.java

index 26589fc..400365a 100644 (file)
@@ -7,6 +7,8 @@ which accompanies this distribution, and is available at
 http://www.eclipse.org/legal/cpl-v10.html
 **********************************************************************/
 
+import org.eclipse.core.runtime.CoreException;
+
 import junit.framework.TestCase;
 
 import net.sourceforge.phpeclipse.phpeditor.PHPParser;
@@ -26,51 +28,63 @@ public class PHPParserTestCase extends TestCase {
    *  Test the PHP Parser with different PHP snippets
    */
   public void testPHPParser() {
-    check("if (isset($test)) { } elseif (isset($lang)) { }");
-    check("require_once(\"mainfile.php\");  ");
-    check("if (eregi(\"footer.php\",$PHP_SELF)) {\n" + "Header(\"Location: index.php\");\n" + "die();\n" + "}\n");
-    check("while (eregi(\"footer.php\",$PHP_SELF)) {\n" + "Header(\"Location: index.php\");\n" + "die();\n" + "}\n");
-    check("while (eregi(\"footer.php\",$PHP_SELF)) :\n" + "Header(\"Location: index.php\");\n" + "die();\n" + "endwhile;\n");
-    check("$tipath = \"images/topics/\";");
-    check("$reasons = array(\"1\", \"2\",\"test\");");
-    check("if ($home == 1) { message_box(); blocks(Center);}");
-    check("$bresult = sql_query(\"select * from \".$prefix.\"_banner WHERE type='0' AND active='1'\", $dbi);");
-    check("switch($func) {\n case \"f1\":\n f1();\n break; \n default: \n f0(); \n break;\n }");
-    check("list ($catid) = sql_fetch_row($result, $dbi);");
-    check("if (!$name) { \n }");
-    check("mt_srand((double)microtime()*1000000);");
-    check("\"\\\"\";");
-    check("$v->read();");
-    check("$alttext = ereg_replace(\"\\\"\", \"\", $alttext);");
-    check("$message .= \"\"._THISISAUTOMATED.\"\\n\\n\";");
-    check("if (!empty($pass) AND $pass==$passwd) { }");
-    check("$AllowableHTML = array(\"b\"=>1,\n \"i\"=>1);");
-    check("if ($term{0}!=$firstChar) {}");
-    check("echo \"<center><b>\"._NOADMINYET.\"</b></center><br><br>\"\n"
-    + ".\"<form action=\\\"admin.php\\\" method=\\\"post\\\">\"\n"
-    + ".\"<tr><td><b>\"._NICKNAME.\":</b></td><td><input type=\\\"text\\\" name=\\\"name\\\" size=\\\"30\\\" maxlength=\\\"25\\\"></td></tr>\"\n"
-    +";");
-    check("/* \n overLib is from Eric Bosrup (http://www.bosrup.com/web/overlib/) \n */");
-    check("if ($arrAtchCookie[1]==0 && $IdAtchPostId!=null){  } ");
-    check("$arrAtchCookie[1] -= filesize(realpath($AtchTempDir).\"/\".$xattachlist)/ 1024; ");
-    check("if (!isset($message)){ \n"
-    + "$message = $myrow[post_text];\n"
-    + "$message = eregi_replace(\"\\[addsig]\", \"\\n-----------------\\n\" .    $myrow[user_sig], $message); \n"
-    +"$message = str_replace(\"<BR>\", \"\\n\", $message); \n"
-    +"$message = str_replace(\"<br>\", \"\\n\", $message); \n } ");
-    check("do {$array[] = array(\"$myrow[uid]\" => \"$myrow[uname]\"); } while($myrow = mysql_fetch_array($result));");
-    check("$ol = new Overlib();");
+    checkHTML("<?php phpinfo(); ?>");
+    
+    checkPHP("if (isset($test)) { } elseif (isset($lang)) { }");
+    checkPHP("require_once(\"mainfile.php\");  ");
+    checkPHP("if (eregi(\"footer.php\",$PHP_SELF)) {\n" + "Header(\"Location: index.php\");\n" + "die();\n" + "}\n");
+    checkPHP("while (eregi(\"footer.php\",$PHP_SELF)) {\n" + "Header(\"Location: index.php\");\n" + "die();\n" + "}\n");
+    checkPHP("while (eregi(\"footer.php\",$PHP_SELF)) :\n" + "Header(\"Location: index.php\");\n" + "die();\n" + "endwhile;\n");
+    checkPHP("$tipath = \"images/topics/\";");
+    checkPHP("$reasons = array(\"1\", \"2\",\"test\");");
+    checkPHP("if ($home == 1) { message_box(); blocks(Center);}");
+    checkPHP("$bresult = sql_query(\"select * from \".$prefix.\"_banner WHERE type='0' AND active='1'\", $dbi);");
+    checkPHP("switch($func) {\n case \"f1\":\n f1();\n break; \n default: \n f0(); \n break;\n }");
+    checkPHP("list ($catid) = sql_fetch_row($result, $dbi);");
+    checkPHP("if (!$name) { \n }");
+    checkPHP("mt_srand((double)microtime()*1000000);");
+    checkPHP("\"\\\"\";");
+    checkPHP("$v->read();");
+    checkPHP("$alttext = ereg_replace(\"\\\"\", \"\", $alttext);");
+    checkPHP("$message .= \"\"._THISISAUTOMATED.\"\\n\\n\";");
+    checkPHP("if (!empty($pass) AND $pass==$passwd) { }");
+    checkPHP("$AllowableHTML = array(\"b\"=>1,\n \"i\"=>1);");
+    checkPHP("if ($term{0}!=$firstChar) {}");
+    checkPHP(
+      "echo \"<center><b>\"._NOADMINYET.\"</b></center><br><br>\"\n"
+        + ".\"<form action=\\\"admin.php\\\" method=\\\"post\\\">\"\n"
+        + ".\"<tr><td><b>\"._NICKNAME.\":</b></td><td><input type=\\\"text\\\" name=\\\"name\\\" size=\\\"30\\\" maxlength=\\\"25\\\"></td></tr>\"\n"
+        + ";");
+    checkPHP("/* \n overLib is from Eric Bosrup (http://www.bosrup.com/web/overlib/) \n */");
+    checkPHP("if ($arrAtchCookie[1]==0 && $IdAtchPostId!=null){  } ");
+    checkPHP("$arrAtchCookie[1] -= filesize(realpath($AtchTempDir).\"/\".$xattachlist)/ 1024; ");
+    checkPHP(
+      "if (!isset($message)){ \n"
+        + "$message = $myrow[post_text];\n"
+        + "$message = eregi_replace(\"\\[addsig]\", \"\\n-----------------\\n\" .    $myrow[user_sig], $message); \n"
+        + "$message = str_replace(\"<BR>\", \"\\n\", $message); \n"
+        + "$message = str_replace(\"<br>\", \"\\n\", $message); \n } ");
+    checkPHP("do {$array[] = array(\"$myrow[uid]\" => \"$myrow[uname]\"); } while($myrow = mysql_fetch_array($result));");
+    checkPHP("$ol = new Overlib();");
+    checkPHP("$risultato = mysql_query($sql) or\n    die(mysql_error());");
+  }
+
+  private void checkPHP(String strEval) {
+    try {
+      parser.phpParse(strEval, 1);
+    } catch (CoreException e) {
+    }
   }
 
-  public void check(String strEval) {
-    parser.start(strEval, 1);
+  private void checkHTML(String strEval) {
+    parser.htmlParse(strEval);
   }
 
   /**
    *  The JUnit setup method
    */
   protected void setUp() {
-    parser = new PHPParser();
+    parser = new PHPParser(null);
   }
 
 }
index 3bbd368..a6f236e 100644 (file)
@@ -1,8 +1,14 @@
 package net.sourceforge.phpeclipse.phpeditor;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Hashtable;
 
 import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.ui.texteditor.MarkerUtilities;
 
 /**********************************************************************
 Copyright (c) 2000, 2002 IBM Corp. and others.
@@ -18,6 +24,15 @@ Contributors:
 
 public class PHPParser extends PHPKeywords {
 
+  public static final int ERROR = 2;
+  public static final int WARNING = 1;
+  public static final int INFO = 0;
+  private IFile fileToParse;
+  private ArrayList phpList;
+
+  private int currentPHPString;
+  private boolean phpEnd;
+
   private static HashMap keywordMap = null;
   private String str;
 
@@ -68,6 +83,13 @@ public class PHPParser extends PHPKeywords {
   final static int TT_AMPERSAND = 52;
   final static int TT_DOLLARLISTOPEN = 53;
   final static int TT_TILDE = 54;
+  final static int TT_TILDEASSIGN = 55;
+  final static int TT_MODASSIGN = 56;
+  final static int TT_POWASSIGN = 57;
+  final static int TT_RSHIFTASSIGN = 58;
+  final static int TT_LSHIFTASSIGN = 59;
+  final static int TT_ANDASSIGN = 60;
+  final static int TT_QUESTIONMARK = 61;
 
   final static int TT_ARGOPEN = 128;
   final static int TT_ARGCLOSE = 129;
@@ -108,20 +130,50 @@ public class PHPParser extends PHPKeywords {
    *@param  sess  Description of Parameter
    *@see
    */
-  public PHPParser() {
+  public PHPParser(IFile fileToParse) {
     if (keywordMap == null) {
       keywordMap = new HashMap();
       for (int i = 0; i < PHP_KEYWORS.length; i++) {
         keywordMap.put(PHP_KEYWORS[i], new Integer(PHP_KEYWORD_TOKEN[i]));
       }
     }
+    this.currentPHPString = 0;
+    this.fileToParse = fileToParse;
+    this.phpList = null;
     this.str = "";
     this.token = TT_EOF;
     this.chIndx = 0;
     this.rowCount = 1;
     this.columnCount = 0;
+    this.phpEnd = false;
+
+    //   getNextToken();
+  }
 
-    getNextToken();
+  /**
+   * Create marker for the parse error
+   */
+  protected void setMarker(String message, int lineNumber, int errorLevel) throws CoreException {
+    setMarker(fileToParse, message, lineNumber, errorLevel);
+  }
+
+  public static void setMarker(IFile file, String message, int lineNumber, int errorLevel) throws CoreException {
+
+    Hashtable attributes = new Hashtable();
+    MarkerUtilities.setMessage(attributes, message);
+    switch (errorLevel) {
+      case ERROR :
+        attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));
+        break;
+      case WARNING :
+        attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_WARNING));
+        break;
+      case INFO :
+        attributes.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_INFO));
+        break;
+    }
+    MarkerUtilities.setLineNumber(attributes, lineNumber);
+    MarkerUtilities.createMarker(file, attributes, IMarker.PROBLEM);
   }
 
   private void throwSyntaxError(String error) {
@@ -155,13 +207,16 @@ public class PHPParser extends PHPKeywords {
 
     chIndx = str.length() + 1;
     ch = ' ';
-    token = TT_EOF;
+    //  token = TT_EOF;
+    phpEnd = true;
   }
 
   /**
    * gets the next token from input
    */
   void getNextToken() {
+    phpEnd = false;
+
     while (str.length() > chIndx) {
       ch = str.charAt(chIndx++);
       token = TT_UNDEFINED;
@@ -170,7 +225,9 @@ public class PHPParser extends PHPKeywords {
         columnCount = chIndx;
         continue; // while loop
       }
-
+      if (str.length() == chIndx) {
+        phpEnd = true;
+      }
       if (!Character.isWhitespace(ch)) {
         if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (ch == '$') || (ch == '@')) {
           getIdentifier();
@@ -288,9 +345,19 @@ public class PHPParser extends PHPKeywords {
             token = TT_COMMA;
 
             break;
+          case '?' :
+            token = TT_QUESTIONMARK;
+            break;
           case '~' :
             token = TT_TILDE;
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_TILDEASSIGN;
 
+                break;
+              }
+            }
             break;
           case '.' :
             token = TT_DOT;
@@ -310,7 +377,14 @@ public class PHPParser extends PHPKeywords {
             break;
           case '%' :
             token = TT_MOD;
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_MODASSIGN;
 
+                break;
+              }
+            }
             break;
           case ';' :
             token = TT_SEMICOLON;
@@ -318,7 +392,14 @@ public class PHPParser extends PHPKeywords {
             break;
           case '^' :
             token = TT_POW;
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_POWASSIGN;
 
+                break;
+              }
+            }
             break;
           case '/' :
             token = TT_DIV;
@@ -447,13 +528,18 @@ public class PHPParser extends PHPKeywords {
               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;
               }
             }
@@ -472,7 +558,13 @@ public class PHPParser extends PHPKeywords {
               if (str.charAt(chIndx) == '<') {
                 chIndx++;
                 token = TT_LSHIFT;
-
+                if (str.length() > chIndx) {
+                  if (str.charAt(chIndx) == '=') {
+                    chIndx++;
+                    token = TT_LSHIFTASSIGN;
+                    break;
+                  }
+                }
                 break;
               }
             }
@@ -493,17 +585,19 @@ public class PHPParser extends PHPKeywords {
 
             break;
           case '&' :
+            token = TT_AMPERSAND;
             if (str.length() > chIndx) {
               if (str.charAt(chIndx) == '&') {
                 chIndx++;
                 token = TT_AND;
-
                 break;
-              } else {
-                token = TT_AMPERSAND;
-
+              }
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_ANDASSIGN;
                 break;
               }
+              break;
             }
 
             break;
@@ -534,6 +628,24 @@ public class PHPParser extends PHPKeywords {
     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;
+      }
+    }
   }
 
   void getIdentifier() {
@@ -644,44 +756,207 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void start(String s, int rowCount) throws SyntaxError {
-    // start up
-    this.str = s;
-    this.token = TT_EOF;
-    this.chIndx = 0;
-    this.rowCount = rowCount;
-    this.columnCount = 0;
-    getNextToken();
-    if (token != TT_EOF) {
-      statementList();
-    }
-    if (token != TT_EOF) {
-      if (token == TT_ARGCLOSE) {
-        throwSyntaxError("too many closing ')'; end-of-file not reached");
+  public void htmlParse(String input) {
+    boolean lineCommentMode = false;
+    boolean multiLineCommentMode = false;
+    boolean stringMode = false;
+
+    StringBuffer buf = new StringBuffer();
+    int lineNumber = 1;
+    int startLineNumber = 1;
+    int startIndex = 0;
+    char ch;
+    char ch2;
+    boolean phpMode = false;
+    boolean phpFound = false;
+
+    phpList = new ArrayList();
+
+    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) {
+          buf.append(ch);
+          if (lineCommentMode && (ch == '\n')) {
+            lineCommentMode = false;
+            // read until end of line
+          } else if ((!stringMode) && (ch == '#')) {
+            // read until end of line
+            lineCommentMode = true;
+            continue;
+          } else if ((!stringMode) && (!multiLineCommentMode) && (ch == '/')) {
+            ch2 = input.charAt(i++);
+            if (ch2 == '/') {
+              lineCommentMode = true;
+              continue;
+            } else if (ch2 == '*') {
+              multiLineCommentMode = true;
+              continue;
+            } else {
+              i--;
+            }
+          } else if (ch == '*' && multiLineCommentMode) {
+            ch2 = input.charAt(i++);
+            if (ch2 == '/') {
+              multiLineCommentMode = false;
+              continue;
+            } else {
+              i--;
+            }
+          } else if (ch == '\\' && stringMode) {
+            ch2 = input.charAt(i++);
+            if (ch2 == '"') {
+              continue;
+            } else {
+              i--;
+            }
+          } else if ((!lineCommentMode) && (!multiLineCommentMode) && (ch == '"')) {
+            if (stringMode) {
+              stringMode = false;
+            } else {
+              stringMode = true;
+            }
+            continue;
+          }
+          if (lineCommentMode || multiLineCommentMode || stringMode) {
+            continue;
+          }
+
+          if (ch == '?') {
+            ch2 = input.charAt(i++);
+            if (ch2 == '>') {
+              // php end
+              phpMode = false;
+              phpList.add(new PHPString(input.substring(startIndex, i - 2), startLineNumber));
+              continue;
+            }
+            i--;
+          }
+        } else {
+        }
       }
-      if (token == TT_LISTCLOSE) {
-        throwSyntaxError("too many closing '}'; end-of-file not reached");
+      if (!phpFound) {
+        setMarker("No PHP source code found.", lineNumber, PHPParser.INFO);
+      } else {
+        //        for (int j=0;j<phpList.size();j++) {
+        //          String temp = ((PHPString)phpList.get(j)).getPHPString();
+        //          int startIndx = temp.length()-10;
+        //          if (startIndx<0) {
+        //            startIndx = 0; 
+        //          }
+        //          System.out.println(temp.substring(startIndx)+"?>");
+        //        }
+        phpParse(null, 1);
+        //        PHPString temp;
+        //        for(int j=0;j<phpList.size();j++) {
+        //          temp = (PHPString) phpList.get(j);
+        //          parser.start(temp.getPHPString(), temp.getLineNumber());
+        //        } 
+      }
+    } catch (CoreException e) {
+    }
+  }
+
+  public void phpParse(String s, int rowCount) throws CoreException {
+    // start up
+    try {
+      this.str = s;
+      if (s == null) {
+        if (phpList.size() != 0) {
+          this.str = ((PHPString) phpList.get(currentPHPString++)).getPHPString();
+        }
       }
-      if (token == TT_PARTCLOSE) {
-        throwSyntaxError("too many closing ']'; end-of-file not reached");
+      this.token = TT_EOF;
+      this.chIndx = 0;
+      this.rowCount = rowCount;
+      this.columnCount = 0;
+      this.phpEnd = false;
+      getNextToken();
+      if (token != TT_EOF && token != TT_UNDEFINED) {
+        statementList();
       }
+      if (token != TT_EOF && token != TT_UNDEFINED) {
+        if (token == TT_ARGCLOSE) {
+          throwSyntaxError("too many closing ')'; end-of-file not reached");
+        }
+        if (token == TT_LISTCLOSE) {
+          throwSyntaxError("too many closing '}'; end-of-file not reached");
+        }
+        if (token == TT_PARTCLOSE) {
+          throwSyntaxError("too many closing ']'; end-of-file not reached");
+        }
 
-      if (token == TT_ARGOPEN) {
-        throwSyntaxError("read character '('; end-of-file not reached");
-      }
-      if (token == TT_LISTOPEN) {
-        throwSyntaxError("read character '{';  end-of-file not reached");
+        if (token == TT_ARGOPEN) {
+          throwSyntaxError("read character '('; end-of-file not reached");
+        }
+        if (token == TT_LISTOPEN) {
+          throwSyntaxError("read character '{';  end-of-file not reached");
+        }
+        if (token == TT_PARTOPEN) {
+          throwSyntaxError("read character '[';  end-of-file not reached");
+        }
+
+        throwSyntaxError("end-of-file not reached");
       }
-      if (token == TT_PARTOPEN) {
-        throwSyntaxError("read character '[';  end-of-file not reached");
+    } catch (SyntaxError err) {
+      if (s != null) {
+        throw err;
+      } else {
+        setMarker(err.getMessage(), err.getLine(), ERROR);
       }
-
-      throwSyntaxError("end-of-file not reached");
     }
-
   }
 
-  public void statementList() {
+  public void statementList() throws CoreException {
     do {
       statement();
       if ((token == TT_LISTCLOSE)
@@ -693,13 +968,14 @@ public class PHPParser extends PHPKeywords {
         || (token == TT_endforeach)
         || (token == TT_endwhile)
         || (token == TT_endswitch)
-        || (token == TT_EOF)) {
+        || (token == TT_EOF)
+        || (token == TT_UNDEFINED)) {
         return;
       }
     } while (true);
   }
 
-  public void compoundStatement() {
+  public void compoundStatement() throws CoreException {
     // '{' [statement-list] '}'
     if (token == TT_LISTOPEN) {
       getNextToken();
@@ -716,7 +992,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void statement() {
+  public void statement() throws CoreException {
     if (token > TT_KEYWORD && token != TT_list) {
       String keyword = identifier;
       if (token == TT_include || token == TT_include_once) {
@@ -725,7 +1001,7 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' character after 'include' or 'include_once' expected.");
           }
         }
@@ -737,7 +1013,7 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' character after 'require' or 'require_once' expected.");
           }
         }
@@ -861,7 +1137,7 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after do-while statement.");
           }
         }
@@ -900,7 +1176,7 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
           }
         }
@@ -912,19 +1188,18 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after 'echo' statement.");
           }
         }
         return;
-
       } else if (token == TT_print) {
         getNextToken();
         expression();
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after 'print' statement.");
           }
         }
@@ -936,7 +1211,7 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after 'global' or 'static' statement.");
           }
         }
@@ -958,25 +1233,25 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after 'unset' statement.");
           }
         }
         return;
 
-      } else if (token == TT_exit || token == TT_die) {
-        getNextToken();
-        if (token != TT_SEMICOLON) {
-          exitStatus();
-        }
-        if (token == TT_SEMICOLON) {
-          getNextToken();
-        } else {
-          if (token != TT_EOF) {
-            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
-          }
-        }
-        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.");
+        //          }
+        //        }
+        //        return;
 
       } else if (token == TT_define) {
         getNextToken();
@@ -1000,7 +1275,7 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_SEMICOLON) {
           getNextToken();
         } else {
-          if (token != TT_EOF) {
+          if (!phpEnd) {
             throwSyntaxError("';' expected after 'define' statement.");
           }
         }
@@ -1038,7 +1313,7 @@ public class PHPParser extends PHPKeywords {
         getNextToken();
         return;
       } else {
-        if (token != TT_EOF) {
+        if (!phpEnd) {
           throwSyntaxError("';' expected after expression.");
         }
       }
@@ -1064,7 +1339,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void classBody() {
+  public void classBody() throws CoreException {
     //'{' [class-element-list] '}'
     if (token == TT_LISTOPEN) {
       getNextToken();
@@ -1081,13 +1356,13 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void classElementList() {
+  public void classElementList() throws CoreException {
     do {
       classElement();
-    } while (token != TT_function || token != TT_var);
+    } while (token == TT_function || token == TT_var);
   }
 
-  public void classElement() {
+  public void classElement() throws CoreException {
     //class-property
     //function-definition
     if (token == TT_function) {
@@ -1124,7 +1399,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void functionDefinition() {
+  public void functionDefinition() throws CoreException {
     functionDeclarator();
     compoundStatement();
   }
@@ -1175,7 +1450,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void labeledStatementList() {
+  public void labeledStatementList() throws CoreException {
     if (token != TT_case && token != TT_default) {
       throwSyntaxError("'case' or 'default' expected.");
     }
@@ -1186,6 +1461,10 @@ public class PHPParser extends PHPKeywords {
         if (token == TT_DDOT) {
           getNextToken();
           statementList();
+        } else if (token == TT_SEMICOLON) {
+          setMarker("':' expected after 'case' keyword found ';'.", rowCount, PHPParser.INFO);
+          getNextToken();
+          statementList();
         } else {
           throwSyntaxError("':' character after 'case' constant expected.");
         }
@@ -1254,7 +1533,7 @@ public class PHPParser extends PHPKeywords {
   //  public void definitionStatement() {
   //  }
 
-  public void ifStatement() {
+  public void ifStatement() throws CoreException {
     // ':' statement-list [elseif-list] [else-colon-statement] 'endif' ';'
     if (token == TT_DDOT) {
       getNextToken();
@@ -1311,7 +1590,7 @@ public class PHPParser extends PHPKeywords {
       }
     }
   }
-  public void elseifStatementList() {
+  public void elseifStatementList() throws CoreException {
     do {
       elseifStatement();
       switch (token) {
@@ -1338,7 +1617,7 @@ public class PHPParser extends PHPKeywords {
     } while (true);
   }
 
-  public void elseifStatement() {
+  public void elseifStatement() throws CoreException {
     if (token == TT_ARGOPEN) {
       getNextToken();
       expression();
@@ -1354,7 +1633,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void switchStatement() {
+  public void switchStatement() throws CoreException {
     if (token == TT_DDOT) {
       // ':' [labeled-statement-list] 'endswitch' ';'
       getNextToken();
@@ -1384,7 +1663,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void forStatement() {
+  public void forStatement() throws CoreException {
     if (token == TT_DDOT) {
       getNextToken();
       statementList();
@@ -1401,7 +1680,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void whileStatement() {
+  public void whileStatement() throws CoreException {
     // ':' statement-list 'endwhile' ';'
     if (token == TT_DDOT) {
       getNextToken();
@@ -1419,7 +1698,7 @@ public class PHPParser extends PHPKeywords {
     }
   }
 
-  public void foreachStatement() {
+  public void foreachStatement() throws CoreException {
     if (token == TT_DDOT) {
       getNextToken();
       statementList();
@@ -1579,6 +1858,33 @@ public class PHPParser extends PHPKeywords {
           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.");
+        //          }
+        //        }
+        //        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) {
@@ -1756,6 +2062,24 @@ public class PHPParser extends PHPKeywords {
     } 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();
     }
   }
 
@@ -1829,9 +2153,23 @@ public class PHPParser extends PHPKeywords {
     } while (true);
   }
 
+  public void ternaryExpression() {
+    equalityExpression();
+    if (token == TT_QUESTIONMARK) {
+      getNextToken();
+      expression();
+      if (token == TT_DDOT) {
+        getNextToken();
+        expression();
+      } else {
+        throwSyntaxError("':' expected in ternary operator '? :'.");
+      }
+    }
+  }
+
   public void andExpression() {
     do {
-      equalityExpression();
+      ternaryExpression();
       if (token != TT_AMPERSAND) {
         return;
       }
@@ -1942,6 +2280,32 @@ public class PHPParser extends PHPKeywords {
 
   public void constant() {
     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;