Added first PHP parser version (doesn't work correct actually)
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPParser.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParser.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParser.java
new file mode 100644 (file)
index 0000000..e2f1dce
--- /dev/null
@@ -0,0 +1,994 @@
+package net.sourceforge.phpeclipse.phpeditor;
+
+import java.util.HashMap;
+
+import net.sourceforge.phpeclipse.phpeditor.php.PHPKeywords;
+
+/**********************************************************************
+Copyright (c) 2000, 2002 IBM Corp. and others.
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Common Public License v1.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/cpl-v10.html
+
+Contributors:
+    IBM Corporation - Initial implementation
+    Klaus Hartlage - www.eclipseproject.de
+**********************************************************************/
+
+public class PHPParser extends PHPKeywords {
+
+  private static HashMap keywordMap = null;
+  private String str;
+
+  // current character
+  char ch;
+  // current token
+  int token;
+
+  // row counter for syntax errors:
+  int rowCount;
+  // column counter for syntax errors:
+  int columnCount;
+
+  int chIndx;
+
+  // current identifier
+  String identifier;
+
+  Long longNumber;
+  Double doubleNumber;
+
+  final static int TT_EOF = 0;
+  final static int TT_UNDEFINED = 1;
+
+  final static int TT_NOT = 31;
+  final static int TT_DOT = 32;
+  final static int TT_POW = 33;
+  final static int TT_DIVIDE = 34;
+  final static int TT_MULTIPLY = 35;
+  final static int TT_SUBTRACT = 36;
+  final static int TT_ADD = 37;
+  final static int TT_EQUAL = 38;
+  final static int TT_UNEQUAL = 39;
+  final static int TT_GREATER = 40;
+  final static int TT_GREATEREQUAL = 41;
+  final static int TT_LESS = 42;
+  final static int TT_LESSEQUAL = 43;
+  final static int TT_AND = 44;
+  final static int TT_OR = 45;
+  final static int TT_HASH = 46;
+  final static int TT_DDOT = 47;
+  final static int TT_DOTASSIGN = 48;
+
+  final static int TT_SET = 49;
+
+  final static int TT_FOREACH = 51;
+  final static int TT_ARGOPEN = 128;
+  final static int TT_ARGCLOSE = 129;
+  final static int TT_LISTOPEN = 130;
+  final static int TT_LISTCLOSE = 131;
+  final static int TT_PARTOPEN = 132;
+  final static int TT_PARTCLOSE = 133;
+  final static int TT_COMMA = 134;
+  final static int TT_PERCENT = 135;
+  final static int TT_STRING = 136;
+  final static int TT_IDENTIFIER = 138;
+  final static int TT_DIGIT = 139;
+  final static int TT_SEMICOLON = 140;
+  final static int TT_SLOT = 141;
+  final static int TT_SLOTSEQUENCE = 142;
+  final static int TT_DECREMENT = 144;
+  final static int TT_INCREMENT = 145;
+  final static int TT_ADDTO = 146;
+  final static int TT_DIVIDEBY = 147;
+  final static int TT_SUBTRACTFROM = 148;
+  final static int TT_TIMESBY = 149;
+  final static int TT_VARIABLE = 150;
+  final static int TT_INT_NUMBER = 151;
+  final static int TT_DOUBLE_NUMBER = 152;
+  final static int TT_INTERPOLATED_STRING = 153;
+  final static int TT_STRING_CONSTANT = 154;
+  //  final static int TT_AT = 153; // @
+  /**
+   *  Class Constructor.
+   *
+   *@param  s
+   *@param  sess  Description of Parameter
+   *@see
+   */
+  public PHPParser(String s, int rowCount) {
+    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.str = s;
+    this.token = TT_EOF;
+    this.chIndx = 0;
+    this.rowCount = rowCount;
+    this.columnCount = 0;
+
+    getNextToken();
+  }
+
+  private void throwSyntaxError(String error) {
+
+    if (str.length() < chIndx) {
+      chIndx--;
+    }
+    // read until end-of-line
+    int eol = chIndx;
+    while (str.length() > eol) {
+      ch = str.charAt(eol++);
+      if (ch == '\n') {
+        eol--;
+        break;
+      }
+    }
+    throw new SyntaxError(rowCount, chIndx - columnCount, str.substring(columnCount + 1, eol), error);
+  }
+
+  /**
+   *  Method Declaration.
+   *
+   *@see
+   */
+  void getChar() {
+    if (str.length() > chIndx) {
+      ch = str.charAt(chIndx++);
+
+      return;
+    }
+
+    chIndx = str.length() + 1;
+    ch = ' ';
+    token = TT_EOF;
+  }
+
+  /**
+   * gets the next token from input
+   */
+  void getNextToken() {
+    while (str.length() > chIndx) {
+      ch = str.charAt(chIndx++);
+      token = TT_UNDEFINED;
+      if (ch == '\n') {
+        rowCount++;
+        columnCount = chIndx;
+        continue; // while loop
+      }
+
+      if (!Character.isWhitespace(ch)) {
+        if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') || (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;
+                }
+                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
+          while ((str.length() > chIndx) && (str.charAt(chIndx++) != '"')) {
+            if (str.charAt(chIndx) == '\\') {
+              if (str.length() > chIndx) {
+                chIndx++;
+              }
+              if (str.length() > chIndx) {
+                chIndx++;
+              }
+            } else {
+              if (str.charAt(chIndx) == '\n') {
+                rowCount++;
+                columnCount = chIndx;
+              }
+            }
+          }
+          if (str.length() > chIndx) {
+            chIndx++;
+          }
+          token = TT_INTERPOLATED_STRING;
+          return;
+        } else if (ch == '\'') {
+          // read string until end
+          while ((str.length() > chIndx) && (str.charAt(chIndx++) != '\'')) {
+            if (str.charAt(chIndx) == '\\') {
+              if (str.length() > chIndx) {
+                chIndx++;
+              }
+              if (str.length() > chIndx) {
+                chIndx++;
+              }
+            }
+          }
+          if (str.length() > chIndx) {
+            chIndx++;
+          }
+          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_DOT;
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_DOTASSIGN;
+
+                break;
+              }
+            }
+
+            break;
+          case '"' :
+            token = TT_STRING;
+
+            break;
+          case '%' :
+            token = TT_PERCENT;
+
+            break;
+          case ';' :
+            token = TT_SEMICOLON;
+
+            break;
+          case '^' :
+            token = TT_POW;
+
+            break;
+          case '/' :
+            token = TT_DIVIDE;
+
+            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;
+              }
+            }
+
+            break;
+          case '=' :
+            token = TT_SET;
+
+            if (str.length() > chIndx) {
+              ch = str.charAt(chIndx);
+
+              if (ch == '=') {
+                chIndx++;
+                token = TT_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;
+
+                break;
+              }
+            }
+
+            break;
+          case '>' :
+            token = TT_GREATER;
+
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_GREATEREQUAL;
+
+                break;
+              }
+            }
+
+            break;
+          case '<' :
+            token = TT_LESS;
+
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx) == '=') {
+                chIndx++;
+                token = TT_LESSEQUAL;
+
+                break;
+              }
+            }
+
+            break;
+
+          case '|' :
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx++) == '|') {
+                token = TT_OR;
+
+                break;
+              }
+            }
+
+            break;
+          case '&' :
+            if (str.length() > chIndx) {
+              if (str.charAt(chIndx++) == '&') {
+                token = TT_AND;
+
+                break;
+              }
+            }
+
+            break;
+          case ':' :
+            token = TT_DDOT;
+
+            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;
+  }
+
+  void getIdentifier() {
+    StringBuffer ident = new StringBuffer();
+    ident.append(ch);
+
+    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();
+
+    Integer i = (Integer) keywordMap.get(identifier);
+    if (i != null) {
+      token = i.intValue();
+    }
+  }
+
+  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();
+        }
+      }
+    }
+
+    // token = TT_INT_NUMBER;
+
+    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 start() throws SyntaxError {
+    statementList();
+    if (token != TT_EOF) {
+      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");
+      }
+
+      throwSyntaxError("end-of-file not reached");
+    }
+
+  }
+
+  public void statementList() {
+    statement();
+  }
+
+  public void statement() {
+    while (token != TT_UNDEFINED) {
+      if (token > TT_KEYWORD) {
+        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;
+        } else if (token == TT_include || token == TT_include_once) {
+          getNextToken();
+          expression();
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            throwSyntaxError("';' character after 'include' or 'include_once' expected.");
+          }
+          return;
+        } else if (token == TT_require || token == TT_require_once) {
+          getNextToken();
+          constant();
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            throwSyntaxError("';' character after 'require' or 'require_once' expected.");
+          }
+          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 {
+            expression();
+            if (token == TT_SEMICOLON) {
+              getNextToken();
+            } else {
+              throwSyntaxError("';' character after 'for' expected.");
+            }
+          }
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            expression();
+            if (token == TT_SEMICOLON) {
+              getNextToken();
+            } else {
+              throwSyntaxError("';' character after 'for' expected.");
+            }
+          }
+          if (token == TT_ARGCLOSE) {
+            getNextToken();
+          } else {
+            expression();
+            if (token == TT_ARGCLOSE) {
+              getNextToken();
+            } else {
+              throwSyntaxError("')' expected after 'for' condition.");
+            }
+          }
+          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_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 {
+            throwSyntaxError("';' expected after 'continue', 'break' or 'return'.");
+          }
+          return;
+
+        } else if (token == TT_echo) {
+          getNextToken();
+          expressionList();
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            throwSyntaxError("';' expected after 'echo' statement.");
+          }
+          return;
+
+        } else if (token == TT_print) {
+          getNextToken();
+          expression();
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            throwSyntaxError("';' expected after 'print' statement.");
+          }
+          return;
+
+        } else if (token == TT_global || token == TT_static) {
+          getNextToken();
+          variableList();
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            throwSyntaxError("';' expected after 'global' or 'static' statement.");
+          }
+          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 {
+            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 {
+            throwSyntaxError("';' expected after 'exit' or 'die' statement.");
+          }
+          return;
+
+        } else if (token == TT_define) {
+          getNextToken();
+          if (token == TT_ARGOPEN) {
+            getNextToken();
+          } else {
+            throwSyntaxError("'(' expected after 'define' keyword.");
+          }
+          constant();
+          if (token == TT_COMMA) {
+            getNextToken();
+          } else {
+            throwSyntaxError("',' expected after first 'define' constant.");
+          }
+          constant();
+          if (token == TT_ARGCLOSE) {
+            getNextToken();
+          } else {
+            throwSyntaxError("')' expected after 'define' statement.");
+          }
+          if (token == TT_SEMICOLON) {
+            getNextToken();
+          } else {
+            throwSyntaxError("';' expected after 'define' statement.");
+          }
+          return;
+
+        }
+
+      } else {
+        if (token == TT_LISTOPEN) {
+          getNextToken();
+          statementList();
+          if (token == TT_LISTCLOSE) {
+            getNextToken();
+          } else {
+            throwSyntaxError("'}' expected.");
+          }
+        }
+      }
+      expression();
+      if (token == TT_SEMICOLON) {
+        getNextToken();
+      } else {
+        throwSyntaxError("';' expected after expression.");
+      }
+    }
+  }
+
+  public void labeledStatement() {
+  }
+
+  public void expressionStatement() {
+  }
+
+  public 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() {
+  }
+
+  public void ifStatement() {
+  }
+
+  public void switchStatement() {
+  }
+
+  public void forStatement() {
+  }
+
+  public void whileStatement() {
+  }
+
+  public void foreachStatement() {
+  }
+
+  public void exitStatus() {
+    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'.");
+    }
+  }
+
+  public void expressionList() {
+    do {
+      expression();
+      if (token == TT_COMMA) {
+        getNextToken();
+      } else {
+        break;
+      }
+    } while (true);
+  }
+
+  public void expression() {
+    if (token == TT_STRING_CONSTANT || token == TT_INTERPOLATED_STRING) {
+      getNextToken();
+    } else {
+      postfixExpression();
+      //      while (token != TT_SEMICOLON) {
+      //        getNextToken();
+      //      }
+    }
+  }
+
+  public void postfixExpression() {
+
+  }
+
+  public void variableList() {
+    do {
+      variable();
+      if (token == TT_COMMA) {
+        getNextToken();
+      } else {
+        break;
+      }
+    } while (true);
+  }
+
+  public void variable() {
+    if (token == TT_VARIABLE) {
+      getNextToken();
+    } else {
+      throwSyntaxError("$-variable expected in variable-list.");
+    }
+  }
+
+  public void constant() {
+
+  }
+}
\ No newline at end of file