Check in first version
authorbdemsky <bdemsky>
Fri, 3 Feb 2006 01:21:53 +0000 (01:21 +0000)
committerbdemsky <bdemsky>
Fri, 3 Feb 2006 01:21:53 +0000 (01:21 +0000)
27 files changed:
Robust/src/Lex/BooleanLiteral.java [new file with mode: 0644]
Robust/src/Lex/CharacterLiteral.java [new file with mode: 0644]
Robust/src/Lex/Comment.java [new file with mode: 0644]
Robust/src/Lex/DocumentationComment.java [new file with mode: 0644]
Robust/src/Lex/DoubleLiteral.java [new file with mode: 0644]
Robust/src/Lex/EOF.java [new file with mode: 0644]
Robust/src/Lex/EndOfLineComment.java [new file with mode: 0644]
Robust/src/Lex/EscapedUnicodeReader.java [new file with mode: 0644]
Robust/src/Lex/FIFO.java [new file with mode: 0644]
Robust/src/Lex/FloatLiteral.java [new file with mode: 0644]
Robust/src/Lex/Identifier.java [new file with mode: 0644]
Robust/src/Lex/InputElement.java [new file with mode: 0644]
Robust/src/Lex/IntegerLiteral.java [new file with mode: 0644]
Robust/src/Lex/Keyword.java [new file with mode: 0644]
Robust/src/Lex/Lexer.java [new file with mode: 0644]
Robust/src/Lex/Literal.java [new file with mode: 0644]
Robust/src/Lex/LongLiteral.java [new file with mode: 0644]
Robust/src/Lex/NullLiteral.java [new file with mode: 0644]
Robust/src/Lex/NumericLiteral.java [new file with mode: 0644]
Robust/src/Lex/Operator.java [new file with mode: 0644]
Robust/src/Lex/Separator.java [new file with mode: 0644]
Robust/src/Lex/StringLiteral.java [new file with mode: 0644]
Robust/src/Lex/Token.java [new file with mode: 0644]
Robust/src/Lex/TraditionalComment.java [new file with mode: 0644]
Robust/src/Lex/WhiteSpace.java [new file with mode: 0644]
Robust/src/Main/Main.java [new file with mode: 0644]
Robust/src/Parse/java14.cup [new file with mode: 0644]

diff --git a/Robust/src/Lex/BooleanLiteral.java b/Robust/src/Lex/BooleanLiteral.java
new file mode 100644 (file)
index 0000000..f013e64
--- /dev/null
@@ -0,0 +1,13 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class BooleanLiteral extends Literal {
+  Boolean val;
+  BooleanLiteral(boolean b) { this.val = new Boolean(b); }
+
+  Symbol token() { return new Symbol(Sym.BOOLEAN_LITERAL, val); }
+
+  public String toString() { return "BooleanLiteral <"+val.toString()+">"; }
+}
diff --git a/Robust/src/Lex/CharacterLiteral.java b/Robust/src/Lex/CharacterLiteral.java
new file mode 100644 (file)
index 0000000..87596f8
--- /dev/null
@@ -0,0 +1,15 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class CharacterLiteral extends Literal {
+  Character val;
+  CharacterLiteral(char c) { this.val = new Character(c); }
+
+  Symbol token() { return new Symbol(Sym.CHARACTER_LITERAL, val); }
+
+  public String toString() { 
+    return "CharacterLiteral <"+Token.escape(val.toString())+">"; 
+  }
+}
diff --git a/Robust/src/Lex/Comment.java b/Robust/src/Lex/Comment.java
new file mode 100644 (file)
index 0000000..6a0aae4
--- /dev/null
@@ -0,0 +1,26 @@
+package Lex;
+
+abstract class Comment extends InputElement {
+  private StringBuffer comment = new StringBuffer();
+
+  String getComment() { return comment.toString(); }
+
+  void appendLine(String more) { // 'more' is '\n' terminated.
+    int i=0;
+
+    // skip leading white space.
+    for (; i<more.length(); i++)
+      if (!Character.isSpaceChar(more.charAt(i))) 
+       break;
+
+    // skip any leading stars.
+    for (; i<more.length(); i++)
+      if (more.charAt(i)!='*')
+       break;
+
+    // the rest of the string belongs to the comment.
+    if (i<more.length())
+      comment.append(more.substring(i));
+  }
+
+}
diff --git a/Robust/src/Lex/DocumentationComment.java b/Robust/src/Lex/DocumentationComment.java
new file mode 100644 (file)
index 0000000..ddbdf6d
--- /dev/null
@@ -0,0 +1,6 @@
+package Lex;
+
+class DocumentationComment extends Comment {
+  DocumentationComment() { }
+}
+  
diff --git a/Robust/src/Lex/DoubleLiteral.java b/Robust/src/Lex/DoubleLiteral.java
new file mode 100644 (file)
index 0000000..388c861
--- /dev/null
@@ -0,0 +1,10 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class DoubleLiteral extends NumericLiteral {
+  DoubleLiteral(double d) { this.val = new Double(d); }
+
+  Symbol token() { return new Symbol(Sym.FLOATING_POINT_LITERAL, val); }
+}
diff --git a/Robust/src/Lex/EOF.java b/Robust/src/Lex/EOF.java
new file mode 100644 (file)
index 0000000..b64d5d6
--- /dev/null
@@ -0,0 +1,10 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class EOF extends Token {
+  EOF() {}
+  Symbol token() { return new Symbol(Sym.EOF); }
+  public String toString() { return "EOF"; }
+}
diff --git a/Robust/src/Lex/EndOfLineComment.java b/Robust/src/Lex/EndOfLineComment.java
new file mode 100644 (file)
index 0000000..73f4756
--- /dev/null
@@ -0,0 +1,5 @@
+package Lex;
+
+class EndOfLineComment extends Comment {
+  EndOfLineComment(String comment) { appendLine(comment); }
+}
diff --git a/Robust/src/Lex/EscapedUnicodeReader.java b/Robust/src/Lex/EscapedUnicodeReader.java
new file mode 100644 (file)
index 0000000..342bf15
--- /dev/null
@@ -0,0 +1,70 @@
+package Lex;
+
+import java.io.Reader;
+import java.io.FilterReader;
+import java.io.IOException;
+
+public class EscapedUnicodeReader extends FilterReader {
+
+  int pushback=-1;
+  boolean isEvenSlash = true;
+
+  public EscapedUnicodeReader(Reader in) {
+    super(in);
+  }
+  public int read() throws IOException {
+    int r = (pushback==-1)?in.read():pushback; pushback=-1;
+    
+    if (r!='\\') {
+      isEvenSlash=true;
+      return r;
+    } else { // found a backslash;
+      if (!isEvenSlash) { // Only even slashes are eligible unicode escapes.
+       isEvenSlash=true;
+       return r;
+      }
+      
+      // Check for the trailing u.
+      pushback=in.read();
+      if (pushback!='u') {
+       isEvenSlash=false;
+       return '\\';
+      }
+
+      // OK, we've found backslash-u.  
+      // Reset pushback and snarf up all trailing u's.
+      pushback=-1;
+      while((r=in.read())=='u')
+       ;
+      // Now we should find 4 hex digits. 
+      // If we don't, we can raise bloody hell.
+      int val=0;
+      for (int i=0; i<4; i++, r=in.read()) {
+       int d=Character.digit((char)r, 16);
+       if (r<0 || d<0)
+         throw new Error("Invalid unicode escape character.");
+       val = (val*16) + d;
+      }
+      // yeah, we made it.
+      pushback = r;
+      isEvenSlash=true;
+      return val;
+    }
+  }
+  // synthesize array read from single-character read.
+  public int read(char cbuf[], int off, int len) throws IOException {
+    for (int i=0; i<len; i++) {
+      int c = read();
+      if (c==-1) return (i==0)?-1:i; // end of stream reached.
+      else cbuf[i+off] = (char) c;
+    }
+    return len;
+  }
+
+  public boolean markSupported() { return false; }
+
+  public boolean ready() throws IOException {
+    if (pushback!=-1) return true;
+    else return in.ready();
+  }
+}
diff --git a/Robust/src/Lex/FIFO.java b/Robust/src/Lex/FIFO.java
new file mode 100644 (file)
index 0000000..83374a0
--- /dev/null
@@ -0,0 +1,64 @@
+package Lex;
+
+/** FIFO class.  This helps implement the lookahead we need for JSR-14.
+ * Copyright (C) 2002 C. Scott Ananian <cananian@alumni.princeton.edu>
+ * This program is released under the terms of the GPL; see the file
+ * COPYING for more details.  There is NO WARRANTY on this code.
+ */
+
+class FIFO {
+  java_cup.runtime.Symbol[] backing = new java_cup.runtime.Symbol[10];
+  int start=0, end=0;
+  final Getter getter;
+  FIFO(Getter getter) { this.getter = getter; }
+  public boolean isEmpty() { return start==end; }
+  private boolean isFull() {
+    return start==end+1 || (start==0 && end==backing.length-1);
+  }
+  private int size() {
+    return ((end<start)?end+backing.length:end)-start;
+  }
+  public void put(java_cup.runtime.Symbol o) {
+    if (isFull()) {
+      java_cup.runtime.Symbol[] nbacking =
+       new java_cup.runtime.Symbol[backing.length*2];
+      System.arraycopy(backing, start, nbacking, 0, backing.length-start);
+      System.arraycopy(backing, 0, nbacking, backing.length-start, start);
+      start = 0;
+      end = backing.length-1;
+      backing = nbacking;
+    }
+    ASSERT(!isFull());
+    backing[end++] = o;
+    if (end == backing.length)
+      end = 0;
+    ASSERT(!isEmpty());
+  }
+  public java_cup.runtime.Symbol get() throws java.io.IOException {
+    if (isEmpty())
+      put(getter.next());
+    ASSERT(!isEmpty());
+    java_cup.runtime.Symbol o = backing[start++];
+    if (start == backing.length)
+      start = 0;
+    ASSERT(!isFull());
+    return o;
+  }
+  public java_cup.runtime.Symbol peek(int i) throws java.io.IOException {
+    while (i >= size())
+      put(getter.next());
+    int index = start+i;
+    if (index >= backing.length) index -= backing.length;
+    ASSERT(0<= index && index < backing.length);
+    return backing[index];
+  }
+  abstract static class Getter {
+    abstract java_cup.runtime.Symbol next()
+      throws java.io.IOException;
+  }
+  private static void ASSERT(boolean b) {
+    if (!b) throw new RuntimeException();
+  }
+}
+       
+    
diff --git a/Robust/src/Lex/FloatLiteral.java b/Robust/src/Lex/FloatLiteral.java
new file mode 100644 (file)
index 0000000..99abf52
--- /dev/null
@@ -0,0 +1,10 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class FloatLiteral extends NumericLiteral {
+  FloatLiteral(float f) { this.val = new Float(f); }
+
+  Symbol token() { return new Symbol(Sym.FLOATING_POINT_LITERAL, val); }
+}
diff --git a/Robust/src/Lex/Identifier.java b/Robust/src/Lex/Identifier.java
new file mode 100644 (file)
index 0000000..1dcf053
--- /dev/null
@@ -0,0 +1,18 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+public class Identifier extends Token {
+  String identifier;
+  public Identifier(String identifier) { this.identifier=identifier; }
+
+  public String toString() { return "Identifier <"+identifier+">"; }
+
+  /* Ben Walter <bwalter@mit.edu> correctly pointed out that
+   * the first released version of this grammar/lexer did not
+   * return the string value of the identifier in the parser token.
+   * Should be fixed now. ;-) <cananian@alumni.princeton.edu>
+   */
+  Symbol token() { return new Symbol(Sym.IDENTIFIER, identifier); }
+}
diff --git a/Robust/src/Lex/InputElement.java b/Robust/src/Lex/InputElement.java
new file mode 100644 (file)
index 0000000..1185826
--- /dev/null
@@ -0,0 +1,3 @@
+package Lex;
+
+abstract class InputElement {}
diff --git a/Robust/src/Lex/IntegerLiteral.java b/Robust/src/Lex/IntegerLiteral.java
new file mode 100644 (file)
index 0000000..ba3e4ee
--- /dev/null
@@ -0,0 +1,10 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class IntegerLiteral extends NumericLiteral {
+  IntegerLiteral(int i) { this.val = new Integer(i); }
+
+  Symbol token() { return new Symbol(Sym.INTEGER_LITERAL, val); }
+}
diff --git a/Robust/src/Lex/Keyword.java b/Robust/src/Lex/Keyword.java
new file mode 100644 (file)
index 0000000..185d7b5
--- /dev/null
@@ -0,0 +1,70 @@
+package Lex;
+
+import java.util.Hashtable;
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class Keyword extends Token {
+  String keyword;
+  Keyword(String s) { keyword = s; }
+
+  Symbol token() {
+    Integer i = (Integer) key_table.get(keyword);
+    return new Symbol(i.intValue());
+  }
+  public String toString() { return "Keyword <"+keyword+">"; }
+
+  static private final Hashtable key_table = new Hashtable();
+  static {
+    key_table.put("abstract", new Integer(Sym.ABSTRACT));
+    key_table.put("assert", new Integer(Sym.ASSERT));
+    key_table.put("boolean", new Integer(Sym.BOOLEAN));
+    key_table.put("break", new Integer(Sym.BREAK));
+    key_table.put("byte", new Integer(Sym.BYTE));
+    key_table.put("case", new Integer(Sym.CASE));
+    key_table.put("catch", new Integer(Sym.CATCH));
+    key_table.put("char", new Integer(Sym.CHAR));
+    key_table.put("class", new Integer(Sym.CLASS));
+    key_table.put("const", new Integer(Sym.CONST));
+    key_table.put("continue", new Integer(Sym.CONTINUE));
+    key_table.put("default", new Integer(Sym.DEFAULT));
+    key_table.put("do", new Integer(Sym.DO));
+    key_table.put("double", new Integer(Sym.DOUBLE));
+    key_table.put("else", new Integer(Sym.ELSE));
+    key_table.put("enum", new Integer(Sym.ENUM));
+    key_table.put("extends", new Integer(Sym.EXTENDS));
+    key_table.put("final", new Integer(Sym.FINAL));
+    key_table.put("finally", new Integer(Sym.FINALLY));
+    key_table.put("float", new Integer(Sym.FLOAT));
+    key_table.put("for", new Integer(Sym.FOR));
+    key_table.put("goto", new Integer(Sym.GOTO));
+    key_table.put("if", new Integer(Sym.IF));
+    key_table.put("implements", new Integer(Sym.IMPLEMENTS));
+    key_table.put("import", new Integer(Sym.IMPORT));
+    key_table.put("instanceof", new Integer(Sym.INSTANCEOF));
+    key_table.put("int", new Integer(Sym.INT));
+    key_table.put("interface", new Integer(Sym.INTERFACE));
+    key_table.put("long", new Integer(Sym.LONG));
+    key_table.put("native", new Integer(Sym.NATIVE));
+    key_table.put("new", new Integer(Sym.NEW));
+    key_table.put("package", new Integer(Sym.PACKAGE));
+    key_table.put("private", new Integer(Sym.PRIVATE));
+    key_table.put("protected", new Integer(Sym.PROTECTED));
+    key_table.put("public", new Integer(Sym.PUBLIC));
+    key_table.put("return", new Integer(Sym.RETURN));
+    key_table.put("short", new Integer(Sym.SHORT));
+    key_table.put("static", new Integer(Sym.STATIC));
+    key_table.put("strictfp", new Integer(Sym.STRICTFP));
+    key_table.put("super", new Integer(Sym.SUPER));
+    key_table.put("switch", new Integer(Sym.SWITCH));
+    key_table.put("synchronized", new Integer(Sym.SYNCHRONIZED));
+    key_table.put("this", new Integer(Sym.THIS));
+    key_table.put("throw", new Integer(Sym.THROW));
+    key_table.put("throws", new Integer(Sym.THROWS));
+    key_table.put("transient", new Integer(Sym.TRANSIENT));
+    key_table.put("try", new Integer(Sym.TRY));
+    key_table.put("void", new Integer(Sym.VOID));
+    key_table.put("volatile", new Integer(Sym.VOLATILE));
+    key_table.put("while", new Integer(Sym.WHILE));
+  }
+}
diff --git a/Robust/src/Lex/Lexer.java b/Robust/src/Lex/Lexer.java
new file mode 100644 (file)
index 0000000..c803d39
--- /dev/null
@@ -0,0 +1,519 @@
+package Lex;
+
+import java.io.Reader;
+import java.io.LineNumberReader;
+import Parse.Sym;
+
+/* Java lexer.
+ * Copyright (C) 2002 C. Scott Ananian <cananian@alumni.princeton.edu>
+ * This program is released under the terms of the GPL; see the file
+ * COPYING for more details.  There is NO WARRANTY on this code.
+ */
+
+public class Lexer {
+  LineNumberReader reader;
+  boolean isJava12;
+  boolean isJava14;
+  boolean isJava15;
+  String line = null;
+  int line_pos = 1;
+  int line_num = 0;
+  LineList lineL = new LineList(-line_pos, null); // sentinel for line #0
+  
+  public Lexer(Reader reader) {
+    this.reader = new LineNumberReader(new EscapedUnicodeReader(reader));
+    this.isJava12 = true;
+    this.isJava14 = true;
+  }
+  
+  public java_cup.runtime.Symbol nextToken() throws java.io.IOException {
+    java_cup.runtime.Symbol sym =
+      lookahead==null ? _nextToken() : lookahead.get();
+    last = sym;
+    return sym;
+  }
+  private boolean shouldBePLT() throws java.io.IOException {
+    // look ahead to see if this LT should be changed to a PLT
+    if (last==null || last.sym!=Sym.IDENTIFIER)
+      return false;
+    if (lookahead==null) lookahead = new FIFO(new FIFO.Getter() {
+       java_cup.runtime.Symbol next() throws java.io.IOException
+       { return _nextToken(); }
+      });
+    int i=0;
+    // skip past IDENTIFIER (DOT IDENTIFIER)*
+    if (lookahead.peek(i++).sym != Sym.IDENTIFIER)
+      return false;
+    while (lookahead.peek(i).sym == Sym.DOT) {
+      i++;
+      if (lookahead.peek(i++).sym != Sym.IDENTIFIER)
+       return false;
+    }
+    // skip past (LBRACK RBRACK)*
+    while (lookahead.peek(i).sym == Sym.LBRACK) {
+      i++;
+      if (lookahead.peek(i++).sym != Sym.RBRACK)
+       return false;
+    }
+    // now the next sym has to be one of LT GT COMMA EXTENDS IMPLEMENTS
+    switch(lookahead.peek(i).sym) {
+    default:
+      return false;
+    case Sym.LT:
+    case Sym.GT:
+    case Sym.COMMA:
+    case Sym.EXTENDS:
+    case Sym.IMPLEMENTS:
+      return true;
+    }
+  }
+  private java_cup.runtime.Symbol last = null;
+  private FIFO lookahead = null;
+  public java_cup.runtime.Symbol _nextToken() throws java.io.IOException {
+    /* tokens are:
+     *  Identifiers/Keywords/true/false/null (start with java letter)
+     *  numeric literal (start with number)
+     *  character literal (start with single quote)
+     *  string (start with double quote)
+     *  separator (parens, braces, brackets, semicolon, comma, period)
+     *  operator (equals, plus, minus, etc)
+     *  whitespace
+     *  comment (start with slash)
+     */
+    InputElement ie;
+    int startpos, endpos;
+    do {
+      startpos = lineL.head + line_pos;
+      ie = getInputElement();
+      if (ie instanceof DocumentationComment)
+       comment = ((Comment)ie).getComment();
+    } while (!(ie instanceof Token));
+    endpos = lineL.head + line_pos - 1;
+
+    //System.out.println(ie.toString()); // uncomment to debug lexer.
+    java_cup.runtime.Symbol sym = ((Token)ie).token();
+    // fix up left/right positions.
+    sym.left = startpos; sym.right = endpos;
+    // return token.
+    return sym;
+  }
+  public boolean debug_lex() throws java.io.IOException {
+    InputElement ie = getInputElement();
+    System.out.println(ie);
+    return !(ie instanceof EOF);
+  }
+
+  String comment;
+  public String lastComment() { return comment; }
+  public void clearComment() { comment=""; }
+  
+  InputElement getInputElement() throws java.io.IOException {
+    if (line_num == 0)
+      nextLine();
+    if (line==null)
+      return new EOF();
+    if (line.length()<=line_pos) {      // end of line.
+      nextLine();
+      if (line==null)
+       return new EOF();
+    }
+    
+    switch (line.charAt(line_pos)) {
+
+      // White space:
+    case ' ':  // ASCII SP
+    case '\t': // ASCII HT
+    case '\f': // ASCII FF
+    case '\n': // LineTerminator
+      return new WhiteSpace(consume());
+
+      // EOF character:
+    case '\020': // ASCII SUB
+      consume();
+      return new EOF();
+
+      // Comment prefix:
+    case '/':
+      return getComment();
+
+      // else, a Token
+    default:
+      return getToken();
+    }
+  }
+  // May get Token instead of Comment.
+  InputElement getComment() throws java.io.IOException {
+    String comment;
+    // line.charAt(line_pos+0) is '/'
+    switch (line.charAt(line_pos+1)) {
+    case '/': // EndOfLineComment
+      comment = line.substring(line_pos+2);
+      line_pos = line.length();
+      return new EndOfLineComment(comment);
+    case '*': // TraditionalComment or DocumentationComment
+      line_pos += 2;
+      if (line.charAt(line_pos)=='*') { // DocumentationComment
+       return snarfComment(new DocumentationComment());
+      } else { // TraditionalComment
+       return snarfComment(new TraditionalComment());
+      }
+    default: // it's a token, not a comment.
+      return getToken();
+    }
+  }
+
+  Comment snarfComment(Comment c) throws java.io.IOException {
+    StringBuffer text=new StringBuffer();
+    while(true) { // Grab CommentTail
+      while (line.charAt(line_pos)!='*') { // Add NotStar to comment.
+       int star_pos = line.indexOf('*', line_pos);
+       if (star_pos<0) {
+         text.append(line.substring(line_pos));
+         c.appendLine(text.toString()); text.setLength(0);
+         line_pos = line.length();
+         nextLine();
+         if (line==null) 
+           throw new Error("Unterminated comment at end of file.");
+       } else {
+         text.append(line.substring(line_pos, star_pos));
+         line_pos=star_pos;
+       }
+      }
+      // At this point, line.charAt(line_pos)=='*'
+      // Grab CommentTailStar starting at line_pos+1.
+      if (line.charAt(line_pos+1)=='/') { // safe because line ends with '\n'
+       c.appendLine(text.toString()); line_pos+=2; return c;
+      }
+      text.append(line.charAt(line_pos++)); // add the '*'
+    }
+  }
+
+  Token getToken() {
+    // Tokens are: Identifiers, Keywords, Literals, Separators, Operators.
+    switch (line.charAt(line_pos)) {
+      // Separators: (period is a special case)
+    case '(':
+    case ')':
+    case '{':
+    case '}':
+    case '[':
+    case ']':
+    case ';':
+    case ',':
+      return new Separator(consume());
+
+      // Operators:
+    case '=':
+    case '>':
+    case '<':
+    case '!':
+    case '~':
+    case '?':
+    case ':':
+    case '&':
+    case '|':
+    case '+':
+    case '-':
+    case '*':
+    case '/':
+    case '^':
+    case '%':
+      return getOperator();
+    case '\'':
+      return getCharLiteral();
+    case '\"':
+      return getStringLiteral();
+
+      // a period is a special case:
+    case '.':
+      if (Character.digit(line.charAt(line_pos+1),10)!=-1)
+       return getNumericLiteral();
+      else if (isJava15 &&
+              line.charAt(line_pos+1)=='.' &&
+              line.charAt(line_pos+2)=='.') {
+       consume(); consume(); consume();
+       return new Separator('\u2026'); // unicode ellipsis character.
+      } else return new Separator(consume());
+    default: 
+      break;
+    }
+    if (Character.isJavaIdentifierStart(line.charAt(line_pos)))
+      return getIdentifier();
+    if (Character.isDigit(line.charAt(line_pos)))
+      return getNumericLiteral();
+    throw new Error("Illegal character on line "+line_num);
+  }
+
+  static final String[] keywords = new String[] {
+    "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
+    "class", "const", "continue", "default", "do", "double", "else", "enum",
+    "extends", "final", "finally", "float", "for", "goto", "if", 
+    "implements", "import", "instanceof", "int", "interface", "long", 
+    "native", "new", "package", "private", "protected", "public", 
+    "return", "short", "static", "strictfp", "super", "switch",
+    "synchronized", "this", "throw", "throws", "transient", "try", "void",
+    "volatile", "while" };
+  Token getIdentifier() {
+    // Get id string.
+    StringBuffer sb = new StringBuffer().append(consume());
+
+    if (!Character.isJavaIdentifierStart(sb.charAt(0)))
+      throw new Error("Invalid Java Identifier on line "+line_num);
+    while (Character.isJavaIdentifierPart(line.charAt(line_pos)))
+      sb.append(consume());
+    String s = sb.toString();
+    // Now check against boolean literals and null literal.
+    if (s.equals("null")) return new NullLiteral();
+    if (s.equals("true")) return new BooleanLiteral(true);
+    if (s.equals("false")) return new BooleanLiteral(false);
+    // Check against keywords.
+    //  pre-java 1.5 compatibility:
+    if (!isJava15 && s.equals("enum")) return new Identifier(s);
+    //  pre-java 1.4 compatibility:
+    if (!isJava14 && s.equals("assert")) return new Identifier(s);
+    //  pre-java 1.2 compatibility:
+    if (!isJava12 && s.equals("strictfp")) return new Identifier(s);
+    // use binary search.
+    for (int l=0, r=keywords.length; r > l; ) {
+      int x = (l+r)/2, cmp = s.compareTo(keywords[x]);
+      if (cmp < 0) r=x; else l=x+1;
+      if (cmp== 0) return new Keyword(s);
+    }
+    // not a keyword.
+    return new Identifier(s);
+  }
+  NumericLiteral getNumericLiteral() {
+    int i;
+    // leading decimal indicates float.
+    if (line.charAt(line_pos)=='.')
+      return getFloatingPointLiteral();
+    // 0x indicates Hex.
+    if (line.charAt(line_pos)=='0' &&
+       (line.charAt(line_pos+1)=='x' ||
+        line.charAt(line_pos+1)=='X')) {
+      line_pos+=2; return getIntegerLiteral(/*base*/16);
+    }
+    // otherwise scan to first non-numeric
+    for (i=line_pos; Character.digit(line.charAt(i),10)!=-1; )
+      i++;
+    switch(line.charAt(i)) { // discriminate based on first non-numeric
+    case '.':
+    case 'f':
+    case 'F':
+    case 'd':
+    case 'D':
+    case 'e':
+    case 'E':
+      return getFloatingPointLiteral();
+    case 'L':
+    case 'l':
+    default:
+      if (line.charAt(line_pos)=='0')
+       return getIntegerLiteral(/*base*/8);
+      return getIntegerLiteral(/*base*/10);
+    }
+  }
+  NumericLiteral getIntegerLiteral(int radix) {
+    long val=0;
+    while (Character.digit(line.charAt(line_pos),radix)!=-1)
+      val = (val*radix) + Character.digit(consume(),radix);
+    if (line.charAt(line_pos) == 'l' ||
+       line.charAt(line_pos) == 'L') {
+      consume();
+      return new LongLiteral(val);
+    } 
+    // we compare MAX_VALUE against val/2 to allow constants like
+    // 0xFFFF0000 to get past the test. (unsigned long->signed int)
+    if ((val/2) > Integer.MAX_VALUE ||
+        val    < Integer.MIN_VALUE)
+      throw new Error("Constant does not fit in integer on line "+line_num);
+    return new IntegerLiteral((int)val);
+  }
+  NumericLiteral getFloatingPointLiteral() {
+    String rep = getDigits();
+    if (line.charAt(line_pos)=='.')
+      rep+=consume() + getDigits();
+    if (line.charAt(line_pos)=='e' ||
+       line.charAt(line_pos)=='E') {
+      rep+=consume();
+      if (line.charAt(line_pos)=='+' ||
+         line.charAt(line_pos)=='-')
+       rep+=consume();
+      rep+=getDigits();
+    }
+    try {
+      switch (line.charAt(line_pos)) {
+      case 'f':
+      case 'F':
+       consume();
+       return new FloatLiteral(Float.valueOf(rep).floatValue());
+      case 'd':
+      case 'D':
+       consume();
+       /* falls through */
+      default:
+       return new DoubleLiteral(Double.valueOf(rep).doubleValue());
+      }
+    } catch (NumberFormatException e) {
+      throw new Error("Illegal floating-point on line "+line_num+": "+e);
+    }
+  }
+  String getDigits() {
+    StringBuffer sb = new StringBuffer();
+    while (Character.digit(line.charAt(line_pos),10)!=-1)
+      sb.append(consume());
+    return sb.toString();
+  }
+
+  Operator getOperator() {
+    char first = consume();
+    char second= line.charAt(line_pos);
+
+    switch(first) {
+      // single-character operators.
+    case '~':
+    case '?':
+    case ':':
+      return new Operator(new String(new char[] {first}));
+      // doubled operators
+    case '+':
+    case '-':
+    case '&':
+    case '|':
+      if (first==second) 
+       return new Operator(new String(new char[] {first, consume()}));
+    default:
+      break;
+    }
+    // Check for trailing '='
+    if (second=='=')
+       return new Operator(new String(new char[] {first, consume()}));
+
+    // Special-case '<<', '>>' and '>>>'
+    if ((first=='<' && second=='<') || // <<
+       (first=='>' && second=='>')) {  // >>
+      String op = new String(new char[] {first, consume()});
+      if (first=='>' && line.charAt(line_pos)=='>') // >>>
+       op += consume();
+      if (line.charAt(line_pos)=='=') // <<=, >>=, >>>=
+       op += consume();
+      return new Operator(op);
+    }
+
+    // Otherwise return single operator.
+    return new Operator(new String(new char[] {first}));
+  }
+
+  CharacterLiteral getCharLiteral() {
+    char firstquote = consume();
+    char val;
+    switch (line.charAt(line_pos)) {
+    case '\\':
+      val = getEscapeSequence();
+      break;
+    case '\'':
+      throw new Error("Invalid character literal on line "+line_num);
+    case '\n':
+      throw new Error("Invalid character literal on line "+line_num);
+    default:
+      val = consume();
+      break;
+    }
+    char secondquote = consume();
+    if (firstquote != '\'' || secondquote != '\'')
+      throw new Error("Invalid character literal on line "+line_num);
+    return new CharacterLiteral(val);
+  }
+  StringLiteral getStringLiteral() {
+    char openquote = consume();
+    StringBuffer val = new StringBuffer();
+    while (line.charAt(line_pos)!='\"') {
+      switch(line.charAt(line_pos)) {
+      case '\\':
+       val.append(getEscapeSequence());
+       break;
+      case '\n':
+       throw new Error("Invalid string literal on line " + line_num);
+      default:
+       val.append(consume());
+       break;
+      }
+    }
+    char closequote = consume();
+    if (openquote != '\"' || closequote != '\"')
+      throw new Error("Invalid string literal on line " + line_num);
+    
+    return new StringLiteral(val.toString().intern());
+  }
+
+  char getEscapeSequence() {
+    if (consume() != '\\')
+      throw new Error("Invalid escape sequence on line " + line_num);
+    switch(line.charAt(line_pos)) {
+    case 'b':
+      consume(); return '\b';
+    case 't':
+      consume(); return '\t';
+    case 'n':
+      consume(); return '\n';
+    case 'f':
+      consume(); return '\f';
+    case 'r':
+      consume(); return '\r';
+    case '\"':
+      consume(); return '\"';
+    case '\'':
+      consume(); return '\'';
+    case '\\':
+      consume(); return '\\';
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+      return (char) getOctal(3);
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+      return (char) getOctal(2);
+    default:
+      throw new Error("Invalid escape sequence on line " + line_num);
+    }
+  }
+  int getOctal(int maxlength) {
+    int i, val=0;
+    for (i=0; i<maxlength; i++)
+      if (Character.digit(line.charAt(line_pos), 8)!=-1) {
+       val = (8*val) + Character.digit(consume(), 8);
+      } else break;
+    if ((i==0) || (val>0xFF)) // impossible.
+      throw new Error("Invalid octal escape sequence in line " + line_num);
+    return val;
+  }
+
+  char consume() { return line.charAt(line_pos++); }
+  void nextLine() throws java.io.IOException {
+    line=reader.readLine();
+    if (line!=null) line=line+'\n'; 
+    lineL = new LineList(lineL.head+line_pos, lineL); // for error reporting
+    line_pos=0; 
+    line_num++; 
+  }
+
+  // Deal with error messages.
+  public void errorMsg(String msg, java_cup.runtime.Symbol info) {
+    int n=line_num, c=info.left-lineL.head;
+    for (LineList p = lineL; p!=null; p=p.tail, n--)
+       if (p.head<=info.left) { c=info.left-p.head; break; }
+    System.err.println(msg+" at line "+n);
+    num_errors++;
+  }
+  private int num_errors = 0;
+  public int numErrors() { return num_errors; }
+  
+  class LineList {
+    int head;
+    LineList tail;
+    LineList(int head, LineList tail) { this.head = head; this.tail = tail; }
+  }
+}
diff --git a/Robust/src/Lex/Literal.java b/Robust/src/Lex/Literal.java
new file mode 100644 (file)
index 0000000..e9a50cf
--- /dev/null
@@ -0,0 +1,3 @@
+package Lex;
+
+abstract class Literal extends Token { }
diff --git a/Robust/src/Lex/LongLiteral.java b/Robust/src/Lex/LongLiteral.java
new file mode 100644 (file)
index 0000000..25090ae
--- /dev/null
@@ -0,0 +1,10 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class LongLiteral extends NumericLiteral {
+  LongLiteral(long l) { this.val = new Long(l); }
+
+  Symbol token() { return new Symbol(Sym.INTEGER_LITERAL, val); }
+}
diff --git a/Robust/src/Lex/NullLiteral.java b/Robust/src/Lex/NullLiteral.java
new file mode 100644 (file)
index 0000000..20e6999
--- /dev/null
@@ -0,0 +1,12 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class NullLiteral extends Literal {
+  NullLiteral() { }
+
+  Symbol token() { return new Symbol(Sym.NULL_LITERAL); }
+
+  public String toString() { return "NullLiteral <null>"; }
+}
diff --git a/Robust/src/Lex/NumericLiteral.java b/Robust/src/Lex/NumericLiteral.java
new file mode 100644 (file)
index 0000000..f67a135
--- /dev/null
@@ -0,0 +1,7 @@
+package Lex;
+
+abstract class NumericLiteral extends Literal {
+  Number val;
+
+  public String toString() { return "NumericLiteral <"+val.toString()+">"; }
+}
diff --git a/Robust/src/Lex/Operator.java b/Robust/src/Lex/Operator.java
new file mode 100644 (file)
index 0000000..e1b26da
--- /dev/null
@@ -0,0 +1,58 @@
+package Lex;
+
+import java.util.Hashtable;
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class Operator extends Token {
+  String which;
+  Operator(String which) { this.which = which; }
+
+  public String toString() { return "Operator <"+which+">"; }
+
+  Symbol token() { 
+    Integer i = (Integer) op_table.get(which);
+    return new Symbol(i.intValue()); 
+  }
+
+  static private final Hashtable op_table = new Hashtable();
+  static {
+    op_table.put("=", new Integer(Sym.EQ));
+    op_table.put(">", new Integer(Sym.GT));
+    op_table.put("<", new Integer(Sym.LT));
+    op_table.put("!", new Integer(Sym.NOT));
+    op_table.put("~", new Integer(Sym.COMP));
+    op_table.put("?", new Integer(Sym.QUESTION));
+    op_table.put(":", new Integer(Sym.COLON));
+    op_table.put("==", new Integer(Sym.EQEQ));
+    op_table.put("<=", new Integer(Sym.LTEQ));
+    op_table.put(">=", new Integer(Sym.GTEQ));
+    op_table.put("!=", new Integer(Sym.NOTEQ));
+    op_table.put("&&", new Integer(Sym.ANDAND));
+    op_table.put("||", new Integer(Sym.OROR));
+    op_table.put("++", new Integer(Sym.PLUSPLUS));
+    op_table.put("--", new Integer(Sym.MINUSMINUS));
+    op_table.put("+", new Integer(Sym.PLUS));
+    op_table.put("-", new Integer(Sym.MINUS));
+    op_table.put("*", new Integer(Sym.MULT));
+    op_table.put("/", new Integer(Sym.DIV));
+    op_table.put("&", new Integer(Sym.AND));
+    op_table.put("|", new Integer(Sym.OR));
+    op_table.put("^", new Integer(Sym.XOR));
+    op_table.put("%", new Integer(Sym.MOD));
+    op_table.put("<<", new Integer(Sym.LSHIFT));
+    op_table.put(">>", new Integer(Sym.RSHIFT));
+    op_table.put(">>>", new Integer(Sym.URSHIFT));
+    op_table.put("+=", new Integer(Sym.PLUSEQ));
+    op_table.put("-=", new Integer(Sym.MINUSEQ));
+    op_table.put("*=", new Integer(Sym.MULTEQ));
+    op_table.put("/=", new Integer(Sym.DIVEQ));
+    op_table.put("&=", new Integer(Sym.ANDEQ));
+    op_table.put("|=", new Integer(Sym.OREQ));
+    op_table.put("^=", new Integer(Sym.XOREQ));
+    op_table.put("%=", new Integer(Sym.MODEQ));
+    op_table.put("<<=", new Integer(Sym.LSHIFTEQ));
+    op_table.put(">>=", new Integer(Sym.RSHIFTEQ));
+    op_table.put(">>>=", new Integer(Sym.URSHIFTEQ));
+  }
+}
diff --git a/Robust/src/Lex/Separator.java b/Robust/src/Lex/Separator.java
new file mode 100644 (file)
index 0000000..6a553bf
--- /dev/null
@@ -0,0 +1,30 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class Separator extends Token {
+  char which;
+  Separator(char which) { this.which = which; }
+
+  Symbol token() {
+    switch(which) {
+    case '(': return new Symbol(Sym.LPAREN);
+    case ')': return new Symbol(Sym.RPAREN);
+    case '{': return new Symbol(Sym.LBRACE);
+    case '}': return new Symbol(Sym.RBRACE);
+    case '[': return new Symbol(Sym.LBRACK);
+    case ']': return new Symbol(Sym.RBRACK);
+    case ';': return new Symbol(Sym.SEMICOLON);
+    case ',': return new Symbol(Sym.COMMA);
+    case '.': return new Symbol(Sym.DOT);
+    case '\u2026':  return new Symbol(Sym.ELLIPSIS);
+    default:
+      throw new Error("Invalid separator.");
+    }
+  }
+
+  public String toString() {
+    return "Separator <"+which+">";
+  }
+}
diff --git a/Robust/src/Lex/StringLiteral.java b/Robust/src/Lex/StringLiteral.java
new file mode 100644 (file)
index 0000000..c483020
--- /dev/null
@@ -0,0 +1,15 @@
+package Lex;
+
+import java_cup.runtime.Symbol;
+import Parse.Sym;
+
+class StringLiteral extends Literal {
+  String val;
+  StringLiteral(String s) { this.val = s; }
+
+  Symbol token() { return new Symbol(Sym.STRING_LITERAL, val); }
+
+  public String toString() { 
+    return "StringLiteral <"+Token.escape(val)+">"; 
+  }
+}
diff --git a/Robust/src/Lex/Token.java b/Robust/src/Lex/Token.java
new file mode 100644 (file)
index 0000000..ec3a578
--- /dev/null
@@ -0,0 +1,21 @@
+package Lex;
+
+abstract class Token extends InputElement {
+  abstract java_cup.runtime.Symbol token();
+
+  protected static String escape(String s) {
+    StringBuffer sb = new StringBuffer();
+    for (int i=0; i<s.length(); i++)
+      switch(s.charAt(i)) {
+      case '\t': sb.append("\\t"); break;
+      case '\f': sb.append("\\f"); break;
+      case '\n': sb.append("\\n"); break;
+      default:
+       if ((int)s.charAt(i)<32)
+         sb.append("\\"+Integer.toOctalString((int)s.charAt(i)));
+       else
+         sb.append(s.charAt(i));
+      }
+    return sb.toString();
+  }
+}
diff --git a/Robust/src/Lex/TraditionalComment.java b/Robust/src/Lex/TraditionalComment.java
new file mode 100644 (file)
index 0000000..4b5d2a8
--- /dev/null
@@ -0,0 +1,5 @@
+package Lex;
+
+class TraditionalComment extends Comment {
+  TraditionalComment() { }
+}
diff --git a/Robust/src/Lex/WhiteSpace.java b/Robust/src/Lex/WhiteSpace.java
new file mode 100644 (file)
index 0000000..fc87301
--- /dev/null
@@ -0,0 +1,18 @@
+package Lex;
+
+class WhiteSpace extends InputElement {
+  char whitespace;
+  WhiteSpace(char which) { this.whitespace=which; }
+
+  public String toString() { 
+    String s;
+    switch(whitespace) {
+    case ' ':  s = "SP"; break;
+    case '\t': s = "HT"; break;
+    case '\f': s = "FF"; break;
+    case '\n': s = "LT"; break;
+    default:   s = "Unknown Whitespace character."; break;
+    }
+    return "Whitespace <"+s+">";
+  }
+}
diff --git a/Robust/src/Main/Main.java b/Robust/src/Main/Main.java
new file mode 100644 (file)
index 0000000..39fcaf7
--- /dev/null
@@ -0,0 +1,26 @@
+package Main;
+
+import java.io.Reader;
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+/* Test skeleton for java parser/lexer.
+ * Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
+ * This is released under the terms of the GPL with NO WARRANTY.
+ * See the file COPYING for more details.
+ */
+
+public class Main {
+  public static void main(String args[]) throws Exception {
+      if (args.length<1) {
+       System.out.println("Must input source file");
+       System.exit(-1);
+      }
+    Reader fr = new BufferedReader(new FileReader(args[0]));
+    Lex.Lexer l = new Lex.Lexer(fr);
+    java_cup.runtime.lr_parser g;
+    g = new Parse.Parser(l);
+    g./*debug_*/parse();
+    System.exit(l.numErrors());
+  }
+}
diff --git a/Robust/src/Parse/java14.cup b/Robust/src/Parse/java14.cup
new file mode 100644 (file)
index 0000000..c3b83df
--- /dev/null
@@ -0,0 +1,879 @@
+package Parse;
+
+import java_cup.runtime.*;
+import Lex.Lexer;
+import Tree.*;
+
+/* Java 1.4 parser for CUP.  
+ * Copyright (C) 2002-2003 C. Scott Ananian <cananian@alumni.princeton.edu>
+ * This program is released under the terms of the GPL; see the file
+ * COPYING for more details.  There is NO WARRANTY on this code.
+ */
+
+/*
+JDK 1.4 Features added:
+  assertion statement.
+  statement_without_trailing_substatement ::= ...
+     |         assert_statement ;
+  assert_statement ::=
+               ASSERT expression SEMICOLON
+       |       ASSERT expression COLON expression SEMICOLON
+       ;
+*/
+parser code  {: 
+  Lexer lexer;
+
+  public Parser(Lexer l) {
+    this();
+    lexer=l;
+  }
+
+  public void syntax_error(java_cup.runtime.Symbol current) {
+    report_error("Syntax error (" + current.sym + ")", current);
+  }
+  public void report_error(String message, java_cup.runtime.Symbol info) {
+    lexer.errorMsg(message, info);
+  }
+:};
+
+scan with {: return lexer.nextToken(); :};
+
+terminal BOOLEAN; // primitive_type
+terminal BYTE, SHORT, INT, LONG, CHAR; // integral_type
+terminal FLOAT, DOUBLE; // floating_point_type
+terminal LBRACK, RBRACK; // array_type
+terminal java.lang.String IDENTIFIER; // name
+terminal DOT; // qualified_name
+terminal SEMICOLON, MULT, COMMA, LBRACE, RBRACE, EQ, LPAREN, RPAREN, COLON;
+terminal PACKAGE; // package_declaration
+terminal IMPORT; // import_declaration
+terminal PUBLIC, PROTECTED, PRIVATE; // modifier
+terminal STATIC; // modifier
+terminal ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, TRANSIENT, VOLATILE;
+terminal CLASS; // class_declaration
+terminal EXTENDS; // super
+terminal IMPLEMENTS; // interfaces
+terminal VOID; // method_header
+terminal THROWS; // throws
+terminal THIS, SUPER; // explicit_constructor_invocation
+terminal INTERFACE; // interface_declaration
+terminal IF, ELSE; // if_then_statement, if_then_else_statement
+terminal SWITCH; // switch_statement
+terminal CASE, DEFAULT; // switch_label
+terminal DO, WHILE; // while_statement, do_statement
+terminal FOR; // for_statement
+terminal BREAK; // break_statement
+terminal CONTINUE; // continue_statement
+terminal RETURN; // return_statement
+terminal THROW; // throw_statement
+terminal TRY; // try_statement
+terminal CATCH; // catch_clause
+terminal FINALLY; // finally
+terminal NEW; // class_instance_creation_expression
+terminal PLUSPLUS; // postincrement_expression
+terminal MINUSMINUS; // postdecrement_expression
+terminal PLUS, MINUS, COMP, NOT, DIV, MOD;
+terminal LSHIFT, RSHIFT, URSHIFT; // shift_expression
+terminal LT, GT, LTEQ, GTEQ, INSTANCEOF; // relational_expression
+terminal EQEQ, NOTEQ; // equality_expression
+terminal AND; // and_expression
+terminal XOR; // exclusive_or_expression
+terminal OR;  // inclusive_or_expression
+terminal ANDAND; // conditional_and_expression
+terminal OROR; // conditional_or_expression
+terminal QUESTION; // conditional_expression
+terminal MULTEQ, DIVEQ, MODEQ, PLUSEQ, MINUSEQ; // assignment_operator
+terminal LSHIFTEQ, RSHIFTEQ, URSHIFTEQ; // assignment_operator
+terminal ANDEQ, XOREQ, OREQ; // assignment_operator
+
+terminal java.lang.Number INTEGER_LITERAL;
+terminal java.lang.Number FLOATING_POINT_LITERAL;
+terminal java.lang.Boolean BOOLEAN_LITERAL;
+terminal java.lang.Character CHARACTER_LITERAL;
+terminal java.lang.String STRING_LITERAL;
+terminal NULL_LITERAL;
+
+// Reserved but unused:
+terminal CONST, GOTO;
+// strictfp keyword, new in Java 1.2
+terminal STRICTFP;
+// assert keyword, new in Java 1.4
+terminal ASSERT; // assert_statement
+// lexer compatibility with Java 1.5
+terminal ELLIPSIS;
+terminal ENUM;
+
+// 19.2) The Syntactic Grammar
+non terminal goal;
+// 19.3) Lexical Structure
+non terminal literal;
+// 19.4) Types, Values, and Variables
+non terminal type, primitive_type, numeric_type;
+non terminal integral_type, floating_point_type;
+non terminal reference_type;
+non terminal class_or_interface_type;
+non terminal class_type, interface_type;
+non terminal array_type;
+// 19.5) Names
+non terminal name, simple_name, qualified_name;
+// 19.6) Packages
+non terminal compilation_unit;
+non terminal package_declaration_opt, package_declaration;
+non terminal import_declarations_opt, import_declarations;
+non terminal type_declarations_opt, type_declarations;
+non terminal import_declaration;
+non terminal single_type_import_declaration;
+non terminal type_import_on_demand_declaration;
+non terminal type_declaration;
+// 19.7) Productions used only in the LALR(1) grammar
+non terminal modifiers_opt, modifiers, modifier;
+// 19.8.1) Class Declaration
+non terminal class_declaration, super, super_opt;
+non terminal interfaces, interfaces_opt, interface_type_list;
+non terminal class_body;
+non terminal class_body_declarations, class_body_declarations_opt;
+non terminal class_body_declaration, class_member_declaration;
+// 19.8.2) Field Declarations
+non terminal field_declaration, variable_declarators, variable_declarator;
+non terminal variable_declarator_id, variable_initializer;
+// 19.8.3) Method Declarations
+non terminal method_declaration, method_header, method_declarator;
+non terminal formal_parameter_list_opt, formal_parameter_list;
+non terminal formal_parameter;
+non terminal throws_opt, throws;
+non terminal class_type_list, method_body;
+// 19.8.4) Static Initializers
+non terminal static_initializer;
+// 19.8.5) Constructor Declarations
+non terminal constructor_declaration, constructor_declarator;
+non terminal constructor_body;
+non terminal explicit_constructor_invocation;
+// 19.9.1) Interface Declarations
+non terminal interface_declaration;
+non terminal extends_interfaces_opt, extends_interfaces;
+non terminal interface_body;
+non terminal interface_member_declarations_opt, interface_member_declarations;
+non terminal interface_member_declaration, constant_declaration;
+non terminal abstract_method_declaration;
+// 19.10) Arrays
+non terminal array_initializer;
+non terminal variable_initializers;
+// 19.11) Blocks and Statements
+non terminal block;
+non terminal block_statements_opt, block_statements, block_statement;
+non terminal local_variable_declaration_statement, local_variable_declaration;
+non terminal statement, statement_no_short_if;
+non terminal statement_without_trailing_substatement;
+non terminal empty_statement;
+non terminal labeled_statement, labeled_statement_no_short_if;
+non terminal expression_statement, statement_expression;
+non terminal if_then_statement;
+non terminal if_then_else_statement, if_then_else_statement_no_short_if;
+non terminal switch_statement, switch_block;
+non terminal switch_block_statement_groups;
+non terminal switch_block_statement_group;
+non terminal switch_labels, switch_label;
+non terminal while_statement, while_statement_no_short_if;
+non terminal do_statement;
+non terminal for_statement, for_statement_no_short_if;
+non terminal for_init_opt, for_init;
+non terminal for_update_opt, for_update;
+non terminal statement_expression_list;
+non terminal identifier_opt;
+non terminal break_statement, continue_statement;
+non terminal return_statement, throw_statement;
+non terminal synchronized_statement, try_statement;
+non terminal catches_opt, catches, catch_clause;
+non terminal finally;
+non terminal assert_statement;
+// 19.12) Expressions
+non terminal primary, primary_no_new_array;
+non terminal class_instance_creation_expression;
+non terminal argument_list_opt, argument_list;
+non terminal array_creation_init, array_creation_uninit;
+non terminal dim_exprs, dim_expr, dims_opt, dims;
+non terminal field_access, method_invocation, array_access;
+non terminal postfix_expression;
+non terminal postincrement_expression, postdecrement_expression;
+non terminal unary_expression, unary_expression_not_plus_minus;
+non terminal preincrement_expression, predecrement_expression;
+non terminal cast_expression;
+non terminal multiplicative_expression, additive_expression;
+non terminal shift_expression, relational_expression, equality_expression;
+non terminal and_expression, exclusive_or_expression, inclusive_or_expression;
+non terminal conditional_and_expression, conditional_or_expression;
+non terminal conditional_expression, assignment_expression;
+non terminal assignment;
+non terminal assignment_operator;
+non terminal expression_opt, expression;
+non terminal constant_expression;
+
+start with goal;
+
+// 19.2) The Syntactic Grammar
+goal ::=       compilation_unit
+       ;
+
+// 19.3) Lexical Structure.
+literal ::=    INTEGER_LITERAL
+       |       FLOATING_POINT_LITERAL
+       |       BOOLEAN_LITERAL
+       |       CHARACTER_LITERAL
+       |       STRING_LITERAL
+       |       NULL_LITERAL
+       ;
+
+// 19.4) Types, Values, and Variables
+type   ::=     primitive_type
+       |       reference_type
+       ;
+primitive_type ::=
+               numeric_type
+       |       BOOLEAN
+       ;
+numeric_type::=        integral_type
+       |       floating_point_type
+       ;
+integral_type ::= 
+               BYTE 
+       |       SHORT 
+       |       INT 
+       |       LONG 
+       |       CHAR 
+       ;
+floating_point_type ::= 
+               FLOAT 
+       |       DOUBLE
+       ;
+
+reference_type ::=
+               class_or_interface_type
+       |       array_type
+       ;
+class_or_interface_type ::= name;
+
+class_type ::= class_or_interface_type;
+interface_type ::= class_or_interface_type;            
+
+array_type ::= primitive_type dims
+       |       name dims
+       ;
+
+// 19.5) Names
+name   ::=     simple_name
+       |       qualified_name
+       ;
+simple_name ::=        IDENTIFIER
+       ;
+qualified_name ::=
+               name DOT IDENTIFIER
+       ;
+
+// 19.6) Packages
+compilation_unit ::=
+               package_declaration_opt 
+               import_declarations_opt
+               type_declarations_opt
+               ;
+package_declaration_opt ::= package_declaration | ;
+import_declarations_opt ::= import_declarations | ;
+type_declarations_opt   ::= type_declarations   | ;
+
+import_declarations ::= 
+               import_declaration
+       |       import_declarations import_declaration
+       ;
+type_declarations ::= 
+               type_declaration
+       |       type_declarations type_declaration
+       ;
+package_declaration ::= 
+               PACKAGE name SEMICOLON
+       ;
+import_declaration ::= 
+               single_type_import_declaration
+       |       type_import_on_demand_declaration
+       ;
+single_type_import_declaration ::= 
+               IMPORT name SEMICOLON
+       ;
+type_import_on_demand_declaration ::=
+               IMPORT name DOT MULT SEMICOLON
+       ;
+type_declaration ::=
+               class_declaration
+       |       interface_declaration
+       |       SEMICOLON
+       ;
+
+// 19.7) Productions used only in the LALR(1) grammar
+modifiers_opt::=
+       |       modifiers
+       ;
+modifiers ::=  modifier
+       |       modifiers modifier
+       ;
+modifier ::=   PUBLIC | PROTECTED | PRIVATE
+       |       STATIC
+       |       ABSTRACT | FINAL | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE
+       |       STRICTFP // note that semantic analysis must check that the
+                        // context of the modifier allows strictfp.
+       ;
+
+// 19.8) Classes
+
+// 19.8.1) Class Declaration:
+class_declaration ::= 
+       modifiers_opt CLASS IDENTIFIER super_opt interfaces_opt class_body
+       ;
+super ::=      EXTENDS class_type
+       ;
+super_opt ::=  
+       |       super
+       ;
+interfaces ::= IMPLEMENTS interface_type_list
+       ;
+interfaces_opt::=
+       |       interfaces 
+       ;
+interface_type_list ::= 
+               interface_type
+       |       interface_type_list COMMA interface_type
+       ;
+class_body ::= LBRACE class_body_declarations_opt RBRACE 
+       ;
+class_body_declarations_opt ::= 
+       |       class_body_declarations ;
+class_body_declarations ::= 
+               class_body_declaration
+       |       class_body_declarations class_body_declaration
+       ;
+class_body_declaration ::=
+               class_member_declaration
+       |       static_initializer
+       |       constructor_declaration
+       |       block
+       ;
+class_member_declaration ::=
+               field_declaration
+       |       method_declaration
+       /* repeat the prod for 'class_declaration' here: */
+       |       modifiers_opt CLASS IDENTIFIER super_opt interfaces_opt class_body
+       |       interface_declaration
+       |       SEMICOLON
+       ;
+
+// 19.8.2) Field Declarations
+field_declaration ::= 
+               modifiers_opt type variable_declarators SEMICOLON
+       ;
+variable_declarators ::=
+               variable_declarator
+       |       variable_declarators COMMA variable_declarator
+       ;
+variable_declarator ::=
+               variable_declarator_id
+       |       variable_declarator_id EQ variable_initializer
+       ;
+variable_declarator_id ::=
+               IDENTIFIER
+       |       variable_declarator_id LBRACK RBRACK
+       ;
+variable_initializer ::=
+               expression
+       |       array_initializer
+       ;
+
+// 19.8.3) Method Declarations
+method_declaration ::=
+               method_header method_body
+       ;
+method_header ::=
+               modifiers_opt type method_declarator throws_opt
+       |       modifiers_opt VOID method_declarator throws_opt
+       ;
+method_declarator ::=
+               IDENTIFIER LPAREN formal_parameter_list_opt RPAREN
+       |       method_declarator LBRACK RBRACK // deprecated
+       // be careful; the above production also allows 'void foo() []'
+       ;
+formal_parameter_list_opt ::=
+       |       formal_parameter_list
+       ;
+formal_parameter_list ::=
+               formal_parameter
+       |       formal_parameter_list COMMA formal_parameter
+       ;
+formal_parameter ::=
+               type variable_declarator_id
+       |       FINAL type variable_declarator_id
+       ;
+throws_opt ::= 
+       |       throws
+       ;
+throws ::=     THROWS class_type_list
+       ;
+class_type_list ::=
+               class_type
+       |       class_type_list COMMA class_type
+       ;
+method_body ::=        block
+       |       SEMICOLON
+       ;
+
+// 19.8.4) Static Initializers
+static_initializer ::=
+               STATIC block
+       ;
+
+// 19.8.5) Constructor Declarations
+constructor_declaration ::=
+               modifiers_opt constructor_declarator throws_opt 
+                       constructor_body
+       ;
+constructor_declarator ::=
+               simple_name LPAREN formal_parameter_list_opt RPAREN
+       ;
+constructor_body ::=
+               LBRACE explicit_constructor_invocation
+                       block_statements RBRACE
+       |       LBRACE explicit_constructor_invocation RBRACE
+       |       LBRACE block_statements RBRACE
+       |       LBRACE RBRACE
+       ;
+explicit_constructor_invocation ::=
+               THIS LPAREN argument_list_opt RPAREN SEMICOLON
+       |       SUPER LPAREN argument_list_opt RPAREN SEMICOLON
+       |       primary DOT THIS LPAREN argument_list_opt RPAREN SEMICOLON
+       |       primary DOT SUPER LPAREN argument_list_opt RPAREN SEMICOLON
+       ;
+
+// 19.9) Interfaces
+
+// 19.9.1) Interface Declarations
+interface_declaration ::=
+               modifiers_opt INTERFACE IDENTIFIER extends_interfaces_opt 
+                       interface_body
+       ;
+extends_interfaces_opt ::=
+       |       extends_interfaces
+       ;
+extends_interfaces ::=
+               EXTENDS interface_type
+       |       extends_interfaces COMMA interface_type
+       ;
+interface_body ::=
+               LBRACE interface_member_declarations_opt RBRACE
+       ;
+interface_member_declarations_opt ::=
+       |       interface_member_declarations
+       ;
+interface_member_declarations ::=
+               interface_member_declaration
+       |       interface_member_declarations interface_member_declaration
+       ;
+interface_member_declaration ::=
+               constant_declaration
+       |       abstract_method_declaration
+       |       class_declaration
+       |       interface_declaration
+       |       SEMICOLON
+       ;
+constant_declaration ::=
+               field_declaration
+       // need to semantically check that modifiers of field declaration
+       // include only PUBLIC, STATIC, or FINAL.  Other modifiers are
+       // disallowed.
+       ;
+abstract_method_declaration ::=
+               method_header SEMICOLON
+       ;
+
+// 19.10) Arrays
+array_initializer ::=
+               LBRACE variable_initializers COMMA RBRACE
+       |       LBRACE variable_initializers RBRACE
+       |       LBRACE COMMA RBRACE
+       |       LBRACE RBRACE
+       ;
+variable_initializers ::=
+               variable_initializer
+       |       variable_initializers COMMA variable_initializer
+       ;
+
+// 19.11) Blocks and Statements
+block ::=      LBRACE block_statements_opt RBRACE
+       ;
+block_statements_opt ::=
+       |       block_statements
+       ;
+block_statements ::=
+               block_statement
+       |       block_statements block_statement
+       ;
+block_statement ::=
+               local_variable_declaration_statement
+       |       statement
+       |       class_declaration
+       |       interface_declaration
+       ;
+local_variable_declaration_statement ::=
+               local_variable_declaration SEMICOLON
+       ;
+local_variable_declaration ::=
+               type variable_declarators
+       |       FINAL type variable_declarators
+       ;
+statement ::=  statement_without_trailing_substatement
+       |       labeled_statement
+       |       if_then_statement
+       |       if_then_else_statement
+       |       while_statement
+       |       for_statement
+       ;
+statement_no_short_if ::=
+               statement_without_trailing_substatement
+       |       labeled_statement_no_short_if
+       |       if_then_else_statement_no_short_if
+       |       while_statement_no_short_if
+       |       for_statement_no_short_if
+       ;
+statement_without_trailing_substatement ::=
+               block
+       |       empty_statement
+       |       expression_statement
+       |       switch_statement
+       |       do_statement
+       |       break_statement
+       |       continue_statement
+       |       return_statement
+       |       synchronized_statement
+       |       throw_statement
+       |       try_statement
+       |       assert_statement
+       ;
+empty_statement ::=
+               SEMICOLON
+       ;
+labeled_statement ::=
+               IDENTIFIER COLON statement
+       ;
+labeled_statement_no_short_if ::=
+               IDENTIFIER COLON statement_no_short_if
+       ;
+expression_statement ::=
+               statement_expression SEMICOLON
+       ;
+statement_expression ::=
+               assignment
+       |       preincrement_expression
+       |       predecrement_expression
+       |       postincrement_expression
+       |       postdecrement_expression
+       |       method_invocation
+       |       class_instance_creation_expression
+       ;
+if_then_statement ::=
+               IF LPAREN expression RPAREN statement
+       ;
+if_then_else_statement ::=
+               IF LPAREN expression RPAREN statement_no_short_if 
+                       ELSE statement
+       ;
+if_then_else_statement_no_short_if ::=
+               IF LPAREN expression RPAREN statement_no_short_if
+                       ELSE statement_no_short_if
+       ;
+switch_statement ::=
+               SWITCH LPAREN expression RPAREN switch_block
+       ;
+switch_block ::=
+               LBRACE switch_block_statement_groups switch_labels RBRACE
+       |       LBRACE switch_block_statement_groups RBRACE
+       |       LBRACE switch_labels RBRACE
+       |       LBRACE RBRACE
+       ;
+switch_block_statement_groups ::=
+               switch_block_statement_group
+       |       switch_block_statement_groups switch_block_statement_group
+       ;
+switch_block_statement_group ::=
+               switch_labels block_statements
+       ;
+switch_labels ::=
+               switch_label
+       |       switch_labels switch_label
+       ;
+switch_label ::=
+               CASE constant_expression COLON
+       |       DEFAULT COLON
+       ;
+
+while_statement ::=
+               WHILE LPAREN expression RPAREN statement
+       ;
+while_statement_no_short_if ::=
+               WHILE LPAREN expression RPAREN statement_no_short_if
+       ;
+do_statement ::=
+               DO statement WHILE LPAREN expression RPAREN SEMICOLON
+       ;
+for_statement ::=
+               FOR LPAREN for_init_opt SEMICOLON expression_opt SEMICOLON
+                       for_update_opt RPAREN statement
+       ;
+for_statement_no_short_if ::=
+               FOR LPAREN for_init_opt SEMICOLON expression_opt SEMICOLON
+                       for_update_opt RPAREN statement_no_short_if
+       ;
+for_init_opt ::=
+       |       for_init
+       ;
+for_init ::=   statement_expression_list
+       |       local_variable_declaration
+       ;
+for_update_opt ::=
+       |       for_update
+       ;
+for_update ::= statement_expression_list
+       ;
+statement_expression_list ::=
+               statement_expression
+       |       statement_expression_list COMMA statement_expression
+       ;
+
+identifier_opt ::= 
+       |       IDENTIFIER
+       ;
+
+break_statement ::=
+               BREAK identifier_opt SEMICOLON
+       ;
+
+continue_statement ::=
+               CONTINUE identifier_opt SEMICOLON
+       ;
+return_statement ::=
+               RETURN expression_opt SEMICOLON
+       ;
+throw_statement ::=
+               THROW expression SEMICOLON
+       ;
+synchronized_statement ::=
+               SYNCHRONIZED LPAREN expression RPAREN block
+       ;
+try_statement ::=
+               TRY block catches
+       |       TRY block catches_opt finally
+       ;
+catches_opt ::=
+       |       catches
+       ;
+catches ::=    catch_clause
+       |       catches catch_clause
+       ;
+catch_clause ::=
+               CATCH LPAREN formal_parameter RPAREN block
+       ;
+finally ::=    FINALLY block
+       ;
+assert_statement ::=
+               ASSERT expression SEMICOLON
+       |       ASSERT expression COLON expression SEMICOLON
+       ;
+
+// 19.12) Expressions
+primary ::=    primary_no_new_array
+       |       array_creation_init
+       |       array_creation_uninit
+       ;
+primary_no_new_array ::=
+               literal
+       |       THIS
+       |       LPAREN expression RPAREN
+       |       class_instance_creation_expression
+       |       field_access
+       |       method_invocation
+       |       array_access
+       |       primitive_type DOT CLASS
+       |       VOID DOT CLASS
+       |       array_type DOT CLASS
+       |       name DOT CLASS
+       |       name DOT THIS
+       ;
+class_instance_creation_expression ::=
+               NEW class_or_interface_type LPAREN argument_list_opt RPAREN
+       |       NEW class_or_interface_type LPAREN argument_list_opt RPAREN class_body
+       |       primary DOT NEW IDENTIFIER
+                       LPAREN argument_list_opt RPAREN
+       |       primary DOT NEW IDENTIFIER
+                       LPAREN argument_list_opt RPAREN class_body
+       |       name DOT NEW IDENTIFIER
+                       LPAREN argument_list_opt RPAREN
+       |       name DOT NEW IDENTIFIER
+                       LPAREN argument_list_opt RPAREN class_body
+       ;
+argument_list_opt ::=
+       |       argument_list
+       ;
+argument_list ::=
+               expression
+       |       argument_list COMMA expression
+       ;
+array_creation_uninit ::=
+               NEW primitive_type dim_exprs dims_opt
+       |       NEW class_or_interface_type dim_exprs dims_opt
+       ;
+array_creation_init ::=
+               NEW primitive_type dims array_initializer
+       |       NEW class_or_interface_type dims array_initializer
+       ;
+dim_exprs ::=  dim_expr
+       |       dim_exprs dim_expr
+       ;
+dim_expr ::=   LBRACK expression RBRACK
+       ;
+dims_opt ::=
+       |       dims
+       ;
+dims ::=       LBRACK RBRACK
+       |       dims LBRACK RBRACK
+       ;
+field_access ::=
+               primary DOT IDENTIFIER
+       |       SUPER DOT IDENTIFIER
+       |       name DOT SUPER DOT IDENTIFIER
+       ;
+method_invocation ::=
+               name LPAREN argument_list_opt RPAREN
+       |       primary DOT IDENTIFIER LPAREN argument_list_opt RPAREN
+       |       SUPER DOT IDENTIFIER LPAREN argument_list_opt RPAREN
+       |       name DOT SUPER DOT IDENTIFIER LPAREN argument_list_opt RPAREN
+       ;
+array_access ::=
+               name LBRACK expression RBRACK
+       |       primary_no_new_array LBRACK expression RBRACK
+       |       array_creation_init LBRACK expression RBRACK
+       ;
+postfix_expression ::=
+               primary
+       |       name
+       |       postincrement_expression
+       |       postdecrement_expression
+       ;
+postincrement_expression ::=
+               postfix_expression PLUSPLUS
+       ;
+postdecrement_expression ::=
+               postfix_expression MINUSMINUS
+       ;
+unary_expression ::=
+               preincrement_expression
+       |       predecrement_expression
+       |       PLUS unary_expression
+       |       MINUS unary_expression
+       |       unary_expression_not_plus_minus
+       ;
+preincrement_expression ::=
+               PLUSPLUS unary_expression
+       ;
+predecrement_expression ::=
+               MINUSMINUS unary_expression
+       ;
+unary_expression_not_plus_minus ::=
+               postfix_expression
+       |       COMP unary_expression
+       |       NOT unary_expression
+       |       cast_expression
+       ;
+cast_expression ::=
+               LPAREN primitive_type dims_opt RPAREN unary_expression
+       |       LPAREN expression RPAREN unary_expression_not_plus_minus
+       |       LPAREN name dims RPAREN unary_expression_not_plus_minus
+       ;
+multiplicative_expression ::=
+               unary_expression
+       |       multiplicative_expression MULT unary_expression
+       |       multiplicative_expression DIV unary_expression
+       |       multiplicative_expression MOD unary_expression
+       ;
+additive_expression ::=
+               multiplicative_expression
+       |       additive_expression PLUS multiplicative_expression
+       |       additive_expression MINUS multiplicative_expression
+       ;
+shift_expression ::=
+               additive_expression
+       |       shift_expression LSHIFT additive_expression
+       |       shift_expression RSHIFT additive_expression
+       |       shift_expression URSHIFT additive_expression
+       ;
+relational_expression ::=
+               shift_expression
+       |       relational_expression LT shift_expression
+       |       relational_expression GT shift_expression
+       |       relational_expression LTEQ shift_expression
+       |       relational_expression GTEQ shift_expression
+       |       relational_expression INSTANCEOF reference_type
+       ;
+equality_expression ::=
+               relational_expression
+       |       equality_expression EQEQ relational_expression
+       |       equality_expression NOTEQ relational_expression
+       ;
+and_expression ::=
+               equality_expression
+       |       and_expression AND equality_expression
+       ;
+exclusive_or_expression ::=
+               and_expression
+       |       exclusive_or_expression XOR and_expression
+       ;
+inclusive_or_expression ::=
+               exclusive_or_expression
+       |       inclusive_or_expression OR exclusive_or_expression
+       ;
+conditional_and_expression ::=
+               inclusive_or_expression
+       |       conditional_and_expression ANDAND inclusive_or_expression
+       ;
+conditional_or_expression ::=
+               conditional_and_expression
+       |       conditional_or_expression OROR conditional_and_expression
+       ;
+conditional_expression ::=
+               conditional_or_expression
+       |       conditional_or_expression QUESTION expression 
+                       COLON conditional_expression
+       ;
+assignment_expression ::=
+               conditional_expression
+       |       assignment
+       ;
+// semantic check necessary here to ensure a valid left-hand side.
+// allowing a parenthesized variable here on the lhs was introduced in
+// JLS 2; thanks to Eric Blake for pointing this out.
+assignment ::= postfix_expression assignment_operator assignment_expression
+       ;
+assignment_operator ::=
+               EQ
+       |       MULTEQ
+       |       DIVEQ
+       |       MODEQ
+       |       PLUSEQ
+       |       MINUSEQ
+       |       LSHIFTEQ
+       |       RSHIFTEQ
+       |       URSHIFTEQ
+       |       ANDEQ
+       |       XOREQ
+       |       OREQ
+       ;
+expression_opt ::=
+       |       expression
+       ;
+expression ::= assignment_expression
+       ;
+constant_expression ::=
+               expression
+       ;