From 125d34e683048a2567f44de53d23e7d648d68ed7 Mon Sep 17 00:00:00 2001 From: bdemsky Date: Fri, 3 Feb 2006 01:21:53 +0000 Subject: [PATCH] Check in first version --- Robust/src/Lex/BooleanLiteral.java | 13 + Robust/src/Lex/CharacterLiteral.java | 15 + Robust/src/Lex/Comment.java | 26 + Robust/src/Lex/DocumentationComment.java | 6 + Robust/src/Lex/DoubleLiteral.java | 10 + Robust/src/Lex/EOF.java | 10 + Robust/src/Lex/EndOfLineComment.java | 5 + Robust/src/Lex/EscapedUnicodeReader.java | 70 ++ Robust/src/Lex/FIFO.java | 64 ++ Robust/src/Lex/FloatLiteral.java | 10 + Robust/src/Lex/Identifier.java | 18 + Robust/src/Lex/InputElement.java | 3 + Robust/src/Lex/IntegerLiteral.java | 10 + Robust/src/Lex/Keyword.java | 70 ++ Robust/src/Lex/Lexer.java | 519 +++++++++++++ Robust/src/Lex/Literal.java | 3 + Robust/src/Lex/LongLiteral.java | 10 + Robust/src/Lex/NullLiteral.java | 12 + Robust/src/Lex/NumericLiteral.java | 7 + Robust/src/Lex/Operator.java | 58 ++ Robust/src/Lex/Separator.java | 30 + Robust/src/Lex/StringLiteral.java | 15 + Robust/src/Lex/Token.java | 21 + Robust/src/Lex/TraditionalComment.java | 5 + Robust/src/Lex/WhiteSpace.java | 18 + Robust/src/Main/Main.java | 26 + Robust/src/Parse/java14.cup | 879 +++++++++++++++++++++++ 27 files changed, 1933 insertions(+) create mode 100644 Robust/src/Lex/BooleanLiteral.java create mode 100644 Robust/src/Lex/CharacterLiteral.java create mode 100644 Robust/src/Lex/Comment.java create mode 100644 Robust/src/Lex/DocumentationComment.java create mode 100644 Robust/src/Lex/DoubleLiteral.java create mode 100644 Robust/src/Lex/EOF.java create mode 100644 Robust/src/Lex/EndOfLineComment.java create mode 100644 Robust/src/Lex/EscapedUnicodeReader.java create mode 100644 Robust/src/Lex/FIFO.java create mode 100644 Robust/src/Lex/FloatLiteral.java create mode 100644 Robust/src/Lex/Identifier.java create mode 100644 Robust/src/Lex/InputElement.java create mode 100644 Robust/src/Lex/IntegerLiteral.java create mode 100644 Robust/src/Lex/Keyword.java create mode 100644 Robust/src/Lex/Lexer.java create mode 100644 Robust/src/Lex/Literal.java create mode 100644 Robust/src/Lex/LongLiteral.java create mode 100644 Robust/src/Lex/NullLiteral.java create mode 100644 Robust/src/Lex/NumericLiteral.java create mode 100644 Robust/src/Lex/Operator.java create mode 100644 Robust/src/Lex/Separator.java create mode 100644 Robust/src/Lex/StringLiteral.java create mode 100644 Robust/src/Lex/Token.java create mode 100644 Robust/src/Lex/TraditionalComment.java create mode 100644 Robust/src/Lex/WhiteSpace.java create mode 100644 Robust/src/Main/Main.java create mode 100644 Robust/src/Parse/java14.cup diff --git a/Robust/src/Lex/BooleanLiteral.java b/Robust/src/Lex/BooleanLiteral.java new file mode 100644 index 00000000..f013e641 --- /dev/null +++ b/Robust/src/Lex/BooleanLiteral.java @@ -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 index 00000000..87596f80 --- /dev/null +++ b/Robust/src/Lex/CharacterLiteral.java @@ -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 index 00000000..6a0aae4b --- /dev/null +++ b/Robust/src/Lex/Comment.java @@ -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 + * 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= 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 index 00000000..99abf527 --- /dev/null +++ b/Robust/src/Lex/FloatLiteral.java @@ -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 index 00000000..1dcf0530 --- /dev/null +++ b/Robust/src/Lex/Identifier.java @@ -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 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. ;-) + */ + 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 index 00000000..11858266 --- /dev/null +++ b/Robust/src/Lex/InputElement.java @@ -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 index 00000000..ba3e4ee3 --- /dev/null +++ b/Robust/src/Lex/IntegerLiteral.java @@ -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 index 00000000..185d7b58 --- /dev/null +++ b/Robust/src/Lex/Keyword.java @@ -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 index 00000000..c803d391 --- /dev/null +++ b/Robust/src/Lex/Lexer.java @@ -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 + * 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; i0xFF)) // 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 index 00000000..e9a50cfe --- /dev/null +++ b/Robust/src/Lex/Literal.java @@ -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 index 00000000..25090aef --- /dev/null +++ b/Robust/src/Lex/LongLiteral.java @@ -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 index 00000000..20e69994 --- /dev/null +++ b/Robust/src/Lex/NullLiteral.java @@ -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 "; } +} diff --git a/Robust/src/Lex/NumericLiteral.java b/Robust/src/Lex/NumericLiteral.java new file mode 100644 index 00000000..f67a135a --- /dev/null +++ b/Robust/src/Lex/NumericLiteral.java @@ -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 index 00000000..e1b26daf --- /dev/null +++ b/Robust/src/Lex/Operator.java @@ -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 index 00000000..6a553bfd --- /dev/null +++ b/Robust/src/Lex/Separator.java @@ -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 index 00000000..c4830203 --- /dev/null +++ b/Robust/src/Lex/StringLiteral.java @@ -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 index 00000000..ec3a578d --- /dev/null +++ b/Robust/src/Lex/Token.java @@ -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"; + } +} diff --git a/Robust/src/Main/Main.java b/Robust/src/Main/Main.java new file mode 100644 index 00000000..39fcaf7b --- /dev/null +++ b/Robust/src/Main/Main.java @@ -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 + * 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 index 00000000..c3b83df2 --- /dev/null +++ b/Robust/src/Parse/java14.cup @@ -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 + * 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 + ; -- 2.34.1