/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* This class is used to parse Java statements and expressions.
* The result is a parse tree.<p>
*
* This class implements an operator precedence parser. Errors are
* reported to the Environment object, if the error can't be
* resolved immediately, a SyntaxError exception is thrown.<p>
*
* Error recovery is implemented by catching SyntaxError exceptions
* and discarding input tokens until an input token is reached that
* is possibly a legal continuation.<p>
*
* The parse tree that is constructed represents the input
* exactly (no rewrites to simpler forms). This is important
* if the resulting tree is to be used for code formatting in
* a programming environment. Currently only documentation comments
* are retained.<p>
*
* The parsing algorithm does NOT use any type information. Changes
* in the type system do not affect the structure of the parse tree.
* This restriction does introduce an ambiguity an expression of the
* form: (e1) e2 is assumed to be a cast if e2 does not start with
* an operator. That means that (a) - b is interpreted as subtract
* b from a and not cast negative b to type a. However, if a is a
* simple type (byte, int, ...) then it is assumed to be a cast.<p>
*
* WARNING: The contents of this source file are not part of any
* supported API. Code that depends on them does so at its own risk:
* they are subject to change or removal without notice.
*
* @author Arthur van Hoff
*/
public
/**
* Create a parser
*/
this.scanner = this;
this.actions = this;
}
/**
* Create a parser, given a scanner.
*/
this.actions = this;
}
/**
* Create a parser, given a scanner and the semantic callback.
*/
this(scanner);
}
/**
* Usually <code>this.actions == (ParserActions)this</code>.
* However, a delegate scanner can produce tokens for this parser,
* in which case <code>(Scanner)this</code> is unused,
* except for <code>this.token</code> and <code>this.pos</code>
* instance variables which are filled from the real scanner
* by <code>this.scan()</code> and the constructor.
*/
// Note: The duplication of methods allows pre-1.1 classes to
// be binary compatible with the new version of the parser,
// which now passes IdentifierTokens to the semantics phase,
// rather than just Identifiers. This change is necessary,
// since the parser is no longer responsible for managing the
// resolution of type names. (That caused the "Vector" bug.)
//
// In a future release, the old "plain-Identifier" methods will
// go away, and the corresponding "IdentifierToken" methods
// may become abstract.
/**
* package declaration
* @deprecated
*/
// By default, call the deprecated version.
// Any application must override one of the packageDeclaration methods.
}
/**
* @deprecated
*/
throw new RuntimeException("beginClass method is abstract");
}
/**
* import class
* @deprecated
*/
// By default, call the deprecated version.
// Any application must override one of the packageDeclaration methods.
}
/**
* @deprecated Use the version with the IdentifierToken arguments.
*/
throw new RuntimeException("importClass method is abstract");
}
/**
* import package
* @deprecated
*/
// By default, call the deprecated version.
// Any application must override one of the importPackage methods.
}
/**
* @deprecated Use the version with the IdentifierToken arguments.
*/
throw new RuntimeException("importPackage method is abstract");
}
/**
* Define class
* @deprecated
*/
IdentifierToken impl[]) {
// By default, call the deprecated version.
// Any application must override one of the beginClass methods.
}
}
return getCurrentClass();
}
/**
* @deprecated Use the version with the IdentifierToken arguments.
*/
throw new RuntimeException("beginClass method is abstract");
}
/**
* Report the current class under construction.
* By default, it's a no-op which returns null.
* It may only be called before the corresponding endClass().
*/
return null;
}
/**
* End class
* @deprecated
*/
// By default, call the deprecated version.
// Any application must override one of the beginClass methods.
}
/**
* @deprecated Use the version with the IdentifierToken arguments.
*/
throw new RuntimeException("endClass method is abstract");
}
/**
* Define a field
* @deprecated
*/
// By default, call the deprecated version.
// Any application must override one of the defineField methods.
}
}
}
}
}
/**
* @deprecated Use the version with the IdentifierToken arguments.
*/
throw new RuntimeException("defineField method is abstract");
}
/*
* A growable array of nodes. It is used as a growable
* buffer to hold argument lists and expression lists.
* I'm not using Vector to make it more efficient.
*/
}
}
return e;
}
return s;
}
/**
* Expect a token, return its value, scan the next token or
* throw an exception.
*/
if (token != t) {
switch (t) {
case IDENT:
break;
default:
break;
}
throw new SyntaxError();
}
scan();
}
/**
* Parse a type expression. Does not parse the []'s.
*/
switch (token) {
case VOID:
case BOOLEAN:
case BYTE:
case CHAR:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
case IDENT:
scan();
}
return e;
}
throw new SyntaxError();
}
/**
* Parse a method invocation. Should be called when the current
* then is the '(' of the argument list.
*/
protected Expression parseMethodExpression(Expression e, Identifier id) throws SyntaxError, IOException {
long p = scan();
int i = argIndex;
scan();
}
}
}
/**
* Parse a new instance expression. Should be called when the current
* token is the '(' of the argument list.
*/
protected Expression parseNewInstanceExpression(long p, Expression outerArg, Expression type) throws SyntaxError, IOException {
int i = argIndex;
scan();
}
}
// x = new Type(arg) { subclass body ... }
}
}
}
}
}
/**
* Parse a primary expression.
*/
switch (token) {
case CHARVAL: {
return new CharExpression(scan(), v);
}
case INTVAL: {
long q = scan();
return new IntExpression(q, v);
}
case LONGVAL: {
long q = scan();
return new LongExpression(q, v);
}
case FLOATVAL: {
float v = scanner.floatValue;
return new FloatExpression(scan(), v);
}
case DOUBLEVAL: {
double v = scanner.doubleValue;
return new DoubleExpression(scan(), v);
}
case STRINGVAL: {
return new StringExpression(scan(), v);
}
case IDENT: {
long p = scan();
}
case TRUE:
return new BooleanExpression(scan(), true);
case FALSE:
return new BooleanExpression(scan(), false);
case NULL:
return new NullExpression(scan());
case THIS: {
}
case SUPER: {
}
case VOID:
case BOOLEAN:
case BYTE:
case CHAR:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
return parseTypeExpression();
case ADD: {
long p = scan();
switch (token) {
case INTVAL: {
long q = scan();
return new IntExpression(q, v);
}
case LONGVAL: {
long q = scan();
return new LongExpression(q, v);
}
case FLOATVAL: {
float v = scanner.floatValue;
return new FloatExpression(scan(), v);
}
case DOUBLEVAL: {
double v = scanner.doubleValue;
return new DoubleExpression(scan(), v);
}
}
return new PositiveExpression(p, parseTerm());
}
case SUB: {
long p = scan();
switch (token) {
case INTVAL: {
return new IntExpression(scan(), v);
}
case LONGVAL: {
return new LongExpression(scan(), v);
}
case FLOATVAL: {
float v = -scanner.floatValue;
return new FloatExpression(scan(), v);
}
case DOUBLEVAL: {
double v = -scanner.doubleValue;
return new DoubleExpression(scan(), v);
}
}
return new NegativeExpression(p, parseTerm());
}
case NOT:
case BITNOT:
case INC:
case DEC:
case LPAREN: {
// bracketed-expr: (expr)
long p = scan();
Expression e = parseExpression();
// cast-expr: (simple-type) expr
return new CastExpression(p, e, parseTerm());
}
switch (token) {
// We handle INC and DEC specially.
// See the discussion in JLS section 15.14.1.
// (Part of fix for 4044502.)
case INC:
// We know this must be a postfix increment.
return new PostIncExpression(scan(), e);
case DEC:
// We know this must be a postfix decrement.
return new PostDecExpression(scan(), e);
case LPAREN:
case CHARVAL:
case INTVAL:
case LONGVAL:
case FLOATVAL:
case DOUBLEVAL:
case STRINGVAL:
case IDENT:
case TRUE:
case FALSE:
case NOT:
case BITNOT:
case THIS:
case SUPER:
case NULL:
case NEW:
// cast-expr: (expr) expr
return new CastExpression(p, e, parseTerm());
}
return new ExprExpression(p, e);
}
case LBRACE: {
// array initializer: {expr1, expr2, ... exprn}
long p = scan();
int i = argIndex;
scan();
break;
}
}
}
return new ArrayExpression(p, exprArgs(i));
}
case NEW: {
long p = scan();
int i = argIndex;
scan();
Expression e = parseExpression();
return new NullExpression(p);
}
Expression e = parseTypeExpression();
if (token == LSQBRACKET) {
while (token == LSQBRACKET) {
scan();
}
}
return new NewArrayExpression(p, e, dims);
} else {
return parseNewInstanceExpression(p, null, e);
}
}
}
// System.err.println("NEAR: " + opNames[token]);
}
/**
* Parse an expression.
*/
return e;
e = more;
}
// this return is bogus
return null;
}
/**
* Given a left-hand term, parse an operator and right-hand term.
*/
if (e != null) {
switch (token) {
case LSQBRACKET: {
// index: expr1[expr2]
long p = scan();
e = new ArrayAccessExpression(p, e, index);
break;
}
case INC:
e = new PostIncExpression(scan(), e);
break;
case DEC:
e = new PostDecExpression(scan(), e);
break;
case FIELD: {
long p = scan();
// class C { class N { ... C.this ... } }
// class C { class N { N(C c){ ... c.this() ... } } }
long q = scan();
e = new ThisExpression(q, e);
e = parseMethodExpression(e, idInit);
} else {
e = new FieldExpression(p, e, idThis);
}
break;
}
// class D extends C.N { D(C.N n) { n.super(); } }
// Also, 'C.super', as in:
// class C extends CS { class N { ... C.super.foo ... } }
// class C extends CS { class N { ... C.super.foo() ... } }
long q = scan();
e = new SuperExpression(q, e);
e = parseMethodExpression(e, idInit);
} else {
// We must check elsewhere that this expression
// does not stand alone, but qualifies a member name.
e = new FieldExpression(p, e, idSuper);
}
break;
}
// new C().new N()
scan();
e = parseNewInstanceExpression(p, e, parseTypeExpression());
break;
}
// just class literals, really
// Class c = C.class;
scan();
e = new FieldExpression(p, e, idClass);
break;
}
e = parseMethodExpression(e, id);
} else {
e = new FieldExpression(p, e, id);
}
break;
}
case INSTANCEOF:
break;
case ADD:
break;
case SUB:
break;
case MUL:
break;
case DIV:
break;
case REM:
break;
case LSHIFT:
break;
case RSHIFT:
break;
case URSHIFT:
break;
case LT:
break;
case LE:
break;
case GT:
break;
case GE:
break;
case EQ:
break;
case NE:
break;
case BITAND:
break;
case BITXOR:
break;
case BITOR:
break;
case AND:
break;
case OR:
break;
case ASSIGN:
break;
case ASGMUL:
break;
case ASGDIV:
break;
case ASGREM:
break;
case ASGADD:
break;
case ASGSUB:
break;
case ASGLSHIFT:
break;
case ASGRSHIFT:
break;
case ASGURSHIFT:
break;
case ASGBITAND:
break;
case ASGBITOR:
break;
case ASGBITXOR:
break;
case QUESTIONMARK: {
long p = scan();
// The grammar in the JLS does not allow assignment
// expressions as the third part of a ?: expression.
// Even though javac has no trouble parsing this,
// check for this case and signal an error.
// (fix for bug 4092958)
if (third instanceof AssignExpression
|| third instanceof AssignOpExpression) {
}
break;
}
default:
return null; // mark end of binary expressions
}
}
return e; // return more binary expression stuff
}
/**
* Recover after a syntax error in a statement. This involves
* discarding tokens until EOF or a possible continuation is
* encountered.
*/
while (true) {
switch (token) {
case EOF:
case RBRACE:
case LBRACE:
case IF:
case FOR:
case WHILE:
case DO:
case TRY:
case CATCH:
case FINALLY:
case BREAK:
case CONTINUE:
case RETURN:
// begin of a statement, return
return true;
case VOID:
case STATIC:
case PUBLIC:
case PRIVATE:
case SYNCHRONIZED:
case INTERFACE:
case CLASS:
case TRANSIENT:
// begin of something outside a statement, panic some more
return false;
case LPAREN:
scan();
break;
case LSQBRACKET:
scan();
break;
default:
// don't know what to do, skip
scan();
break;
}
}
}
/**
* Parse declaration, called after the type expression
* has been parsed and the current token is IDENT.
*/
protected Statement parseDeclaration(long p, int mod, Expression type) throws SyntaxError, IOException {
int i = argIndex;
scan();
}
}
}
/**
* Check if an expression is a legal toplevel expression.
* Only method, inc, dec, and new expression are allowed.
*/
switch (e.getOp()) {
case ASSIGN:
case ASGMUL:
case ASGDIV:
case ASGREM:
case ASGADD:
case ASGSUB:
case ASGLSHIFT:
case ASGRSHIFT:
case ASGURSHIFT:
case ASGBITAND:
case ASGBITOR:
case ASGBITXOR:
case PREINC:
case PREDEC:
case POSTINC:
case POSTDEC:
case METHOD:
case NEWINSTANCE:
return;
}
}
/**
* Parse a statement.
*/
switch (token) {
case SEMICOLON:
case LBRACE:
return parseBlockStatement();
case IF: {
// if-statement: if (expr) stat
// if-statement: if (expr) stat else stat
long p = scan();
Expression c = parseExpression();
Statement t = parseStatement();
scan();
return new IfStatement(p, c, t, parseStatement());
} else {
return new IfStatement(p, c, t, null);
}
}
case ELSE: {
// else-statement: else stat
return parseStatement();
}
case FOR: {
// for-statement: for (decl-expr? ; expr? ; expr?) stat
long p = scan();
Expression e = parseExpression();
} else {
if (mod != 0) {
}
}
}
}
cond = parseExpression();
}
inc = parseExpression();
}
}
}
case WHILE: {
// while-statement: while (expr) stat
long p = scan();
}
case DO: {
// do-statement: do stat while (expr)
long p = scan();
}
case BREAK: {
// break-statement: break ;
long p = scan();
scan();
}
return new BreakStatement(p, label);
}
case CONTINUE: {
// continue-statement: continue ;
long p = scan();
scan();
}
return new ContinueStatement(p, label);
}
case RETURN: {
// return-statement: return ;
// return-statement: return expr ;
long p = scan();
Expression e = null;
e = parseExpression();
}
return new ReturnStatement(p, e);
}
case SWITCH: {
// switch statement: switch ( expr ) stat
long p = scan();
int i = argIndex;
Expression e = parseExpression();
int j = argIndex;
try {
switch (token) {
case CASE:
// case-statement: case expr:
break;
case DEFAULT:
// default-statement: default:
break;
default:
break;
}
} catch (SyntaxError ee) {
argIndex = j;
if (!recoverStatement()) {
throw ee;
}
}
}
return new SwitchStatement(p, e, statArgs(i));
}
case CASE: {
// case-statement: case expr : stat
scan();
}
return parseStatement();
}
case DEFAULT: {
// default-statement: default : stat
scan();
return parseStatement();
}
case TRY: {
// try-statement: try stat catch (type-expr ident) stat finally stat
long p = scan();
int i = argIndex;
boolean catches = false;
Expression e = parseExpression();
// leave check for try (T x, y) for semantic phase
} else {
if (mod != 0) {
}
}
}
Statement s = parseBlockStatement();
// s = new FinallyStatement(p, init, s, 0);
}
Expression t = parseExpression();
// We only catch Throwable's, so this is no longer required
// while (token == LSQBRACKET) {
// t = new ArrayAccessExpression(scan(), t, null);
// expect(RSQBRACKET);
// }
catches = true;
}
if (catches)
s = new TryStatement(p, s, statArgs(i));
scan();
return new FinallyStatement(p, s, parseBlockStatement());
return s;
} else {
return new TryStatement(p, s, null);
}
}
case CATCH: {
// catch-statement: catch (expr ident) stat finally stat
Statement s;
do {
scan();
s = parseBlockStatement();
scan();
s = parseBlockStatement();
}
return s;
}
case FINALLY: {
// finally-statement: finally stat
scan();
return parseBlockStatement();
}
case THROW: {
// throw-statement: throw expr;
long p = scan();
Expression e = parseExpression();
return new ThrowStatement(p, e);
}
case GOTO: {
long p = scan();
}
case SYNCHRONIZED: {
// synchronized-statement: synchronized (expr) stat
long p = scan();
Expression e = parseExpression();
return new SynchronizedStatement(p, e, parseBlockStatement());
}
case INTERFACE:
case CLASS:
// Inner class.
return parseLocalClass(0);
case CONST:
case ABSTRACT:
case FINAL:
case STRICTFP: {
// a declaration of some sort
long p = pos;
// A class which is local to a block is not a member, and so
// cannot be public, private, protected, or static. It is in
// effect private to the block, since it cannot be used outside
// its scope.
//
// However, any class (if it has a name) can be declared final,
// abstract, or strictfp.
| M_STRICTFP );
switch (token) {
case INTERFACE:
case CLASS:
return parseLocalClass(mod);
case BOOLEAN:
case BYTE:
case CHAR:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
case IDENT: {
}
Expression e = parseExpression();
}
// declaration: final expr expr
return s;
}
default:
throw new SyntaxError();
}
}
case VOID:
case STATIC:
case PUBLIC:
case PRIVATE:
case TRANSIENT:
// This is the start of something outside a statement
throw new SyntaxError();
}
long p = pos;
Expression e = parseExpression();
// declaration: expr expr
return s;
}
// label: id: stat
scan();
Statement s = parseStatement();
return s;
}
// it was just an expression...
return new ExpressionStatement(p, e);
}
// compound statement: { stat1 stat2 ... statn }
// We're expecting a block statement. But we'll probably do the
// least damage if we try to parse a normal statement instead.
return parseStatement();
}
long p = scan();
int i = argIndex;
int j = argIndex;
try {
} catch (SyntaxError e) {
argIndex = j;
if (!recoverStatement()) {
throw e;
}
}
}
return new CompoundStatement(p, statArgs(i));
}
/**
* Parse an identifier. ie: a.b.c returns "a.b.c"
* If star is true then "a.b.*" is allowed.
* The return value encodes both the identifier and its location.
*/
return res;
}
scan();
scan();
break;
}
}
}
return res;
}
/**
* @deprecated
* @see #parseName
*/
}
/**
* Parse a type expression, this results in a Type.
* The parse includes trailing array brackets.
*/
Type t;
switch (token) {
case IDENT:
break;
case VOID:
scan();
break;
case BOOLEAN:
scan();
break;
case BYTE:
scan();
break;
case CHAR:
scan();
break;
case SHORT:
scan();
break;
case INT:
scan();
break;
case FLOAT:
scan();
break;
case LONG:
scan();
break;
case DOUBLE:
scan();
break;
default:
throw new SyntaxError();
}
return parseArrayBrackets(t);
}
/**
* Parse the tail of a type expression, which might be array brackets.
* Return the given type, as possibly modified by the suffix.
*/
// Parse []'s
while (token == LSQBRACKET) {
scan();
if (token != RSQBRACKET) {
}
}
return t;
}
/*
* Dealing with argument lists, I'm not using
* Vector for efficiency.
*/
}
}
/**
* Parse a possibly-empty sequence of modifier keywords.
* Return the resulting bitmask.
* Diagnose repeated modifiers, but make no other checks.
* Only modifiers mentioned in the given bitmask are scanned;
* an unmatched modifier must be handled by the caller.
*/
int mod = 0;
while (true) {
// const isn't in java, but handle a common C++ usage gently
scan();
}
int nextmod = 0;
switch (token) {
}
break;
}
}
scan();
}
return mod;
}
/**
* Parse a field.
*/
// Empty fields are not allowed by the JLS but are accepted by
// the compiler, and much code has come to rely on this. It has
// been decided that the language will be extended to legitimize them.
// empty field
scan();
return;
}
// Optional doc comment
// The start of the field
long p = pos;
// Parse the modifiers
// Check for static initializer
// ie: static { ... }
// or an instance initializer (w/o the static).
// static initializer
parseStatement());
return;
}
// Check for inner class
return;
}
// Parse the type
p = pos;
// Check that the type is followed by an Identifier
// (the name of the method or the first variable),
// otherwise it is a constructor.
switch (token) {
case IDENT:
p = scan();
break;
case LPAREN:
// It is a constructor
break;
default:
}
// If the next token is a left-bracket then we
// are dealing with a method or constructor, otherwise it is
// a list of variables
// It is a method or constructor declaration
scan();
aCount = 0;
// Parse argument type and identifier
// (arguments (like locals) are allowed to be final)
// Parse optional array specifier, ie: a[][]
// If the next token is a comma then there are
// more arguments
// Parse argument type and identifier
scan();
// Parse optional array specifier, ie: a[][]
}
}
// Parse optional array sepecifier, ie: foo()[][]
t = parseArrayBrackets(t);
// copy arguments
// Construct the type signature
// Parse and ignore throws clause
scan();
v.addElement(parseName(false));
scan();
v.addElement(parseName(false));
}
}
// Check if it is a method definition or a method declaration
// ie: foo() {...} or foo();
switch (token) {
case LBRACE: // It's a method definition
// Set the state of FP strictness for the body of the method
int oldFPstate = FPstate;
} else {
}
break;
case SEMICOLON:
scan();
break;
default:
// really expected a statement body here
} else {
}
}
return;
}
// It is a list of instance variables
while (true) {
p = pos; // get the current position
// parse the array brackets (if any)
// ie: var[][][]
// Parse the optional initializer
scan();
init = parseExpression();
}
// Define the variable
// If the next token is a comma, then there is more
return;
}
scan();
// The next token must be an identifier
}
}
/**
* Recover after a syntax error in a field. This involves
* discarding tokens until an EOF or a possible legal
* continuation is encountered.
*/
while (true) {
switch (token) {
case EOF:
case STATIC:
case FINAL:
case PUBLIC:
case PRIVATE:
case SYNCHRONIZED:
case TRANSIENT:
case VOID:
case BOOLEAN:
case BYTE:
case CHAR:
case SHORT:
case INT:
case FLOAT:
case LONG:
case DOUBLE:
// possible begin of a field, continue
return;
case LBRACE:
scan();
break;
case LPAREN:
scan();
break;
case LSQBRACKET:
scan();
break;
case RBRACE:
case INTERFACE:
case CLASS:
case IMPORT:
case PACKAGE:
// begin of something outside a class, panic more
throw new SyntaxError();
default:
// don't know what to do, skip
scan();
break;
}
}
}
/**
* Parse a top-level class or interface declaration.
*/
// Parse the modifiers.
}
// set and reset with a stack discipline around methods and named
// classes. Only M_STRICTFP may be set in this word. try...
// finally is not needed to protect setting and resetting because
// there are no error messages based on FPstate.
/**
* Parse a block-local class or interface declaration.
*/
long p = pos;
};
}
/**
* Parse a named class or interface declaration,
* starting at "class" or "interface".
* @arg ctx Syntactic context of the class, one of {PACKAGE CLASS STAT EXPR}.
*/
protected ClassDefinition parseNamedClass(int mod, int ctx, String doc) throws SyntaxError, IOException {
switch (token) {
case INTERFACE:
scan();
mod |= M_INTERFACE;
break;
case CLASS:
scan();
break;
default:
break;
}
int oldFPstate = FPstate;
} else {
// The & (...) isn't really necessary here because we do maintain
// the invariant that FPstate has no extra bits set.
}
// Parse the class name
long p = pos;
return tmp;
}
// Parse extends clause
scan();
scan();
}
}
// Parse implements clause
if (token == IMPLEMENTS) {
scan();
scan();
}
}
}
/**
* Parse the body of a class or interface declaration,
* starting at the left brace.
*/
) throws SyntaxError, IOException {
// Decide which is the super class
"intf.impl.intf");
}
} else {
"multiple.inherit");
}
}
}
// Begin a new class
// Parse fields
try {
parseField();
} catch (SyntaxError e) {
} finally {
}
}
// End the class
return newClass;
}
/**
* Recover after a syntax error in the file.
* This involves discarding tokens until an EOF
* or a possible legal continuation is encountered.
*/
while (true) {
switch (token) {
case CLASS:
case INTERFACE:
// Start of a new source file statement, continue
return;
case LBRACE:
scan();
break;
case LPAREN:
scan();
break;
case LSQBRACKET:
scan();
break;
case EOF:
return;
default:
// Don't know what to do, skip
scan();
break;
}
}
}
/**
* Parse an Java file.
*/
public void parseFile() {
try {
try {
// Package statement
long p = scan();
}
} catch (SyntaxError e) {
recoverFile();
}
try{
// Import statement
long p = scan();
} else {
}
} catch (SyntaxError e) {
recoverFile();
}
}
try {
switch (token) {
case FINAL:
case PUBLIC:
case PRIVATE:
case ABSTRACT:
case CLASS:
case INTERFACE:
case STRICTFP:
// Start of a class
parseClass();
break;
case SEMICOLON:
// Bogus semicolon.
// According to the JLS (7.6,19.6), a TypeDeclaration
// may consist of a single semicolon, however, this
// usage is discouraged (JLS 7.6). In contrast,
// a FieldDeclaration may not be empty, and is flagged
// as an error. See parseField above.
scan();
break;
case EOF:
// The end
return;
default:
// Oops
throw new SyntaxError();
}
} catch (SyntaxError e) {
recoverFile();
}
}
} catch (IOException e) {
return;
}
}
/**
* Usually <code>this.scanner == (Scanner)this</code>.
* However, a delegate scanner can produce tokens for this parser,
* in which case <code>(Scanner)this</code> is unused,
* except for <code>this.token</code> and <code>this.pos</code>
* instance variables which are filled from the real scanner
* by <code>this.scan()</code> and the constructor.
*/
// Design Note: We ought to disinherit Parser from Scanner.
// We also should split out the interface ParserActions from
// Parser, and make BatchParser implement ParserActions,
// not extend Parser. This would split scanning, parsing,
// and class building into distinct responsibility areas.
// (Perhaps tree building could be virtualized too.)
return result;
}
return super.scan();
}
if (scanner != this) {
return;
}
}
}