--- /dev/null
+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()+">"; }
+}
--- /dev/null
+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())+">";
+ }
+}
--- /dev/null
+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));
+ }
+
+}
--- /dev/null
+package Lex;
+
+class DocumentationComment extends Comment {
+ DocumentationComment() { }
+}
+
--- /dev/null
+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); }
+}
--- /dev/null
+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"; }
+}
--- /dev/null
+package Lex;
+
+class EndOfLineComment extends Comment {
+ EndOfLineComment(String comment) { appendLine(comment); }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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();
+ }
+}
+
+
--- /dev/null
+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); }
+}
--- /dev/null
+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); }
+}
--- /dev/null
+package Lex;
+
+abstract class InputElement {}
--- /dev/null
+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); }
+}
--- /dev/null
+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));
+ }
+}
--- /dev/null
+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; }
+ }
+}
--- /dev/null
+package Lex;
+
+abstract class Literal extends Token { }
--- /dev/null
+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); }
+}
--- /dev/null
+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>"; }
+}
--- /dev/null
+package Lex;
+
+abstract class NumericLiteral extends Literal {
+ Number val;
+
+ public String toString() { return "NumericLiteral <"+val.toString()+">"; }
+}
--- /dev/null
+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));
+ }
+}
--- /dev/null
+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+">";
+ }
+}
--- /dev/null
+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)+">";
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+package Lex;
+
+class TraditionalComment extends Comment {
+ TraditionalComment() { }
+}
--- /dev/null
+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+">";
+ }
+}
--- /dev/null
+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());
+ }
+}
--- /dev/null
+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
+ ;