/*
* @(#)Parser.java 1.53 95/11/08 Arthur van Hoff
*
* Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and without
* fee is hereby granted provided that this copyright notice
* appears in all copies. Please refer to the file "copyright.html"
* for further important copyright and licensing information.
*
* SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*/
package sun.tools.java;
import sun.tools.tree.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;
/**
* 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 immediatly, 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>
*
* @author Arthur van Hoff
* @version 1.53, 08 Nov 1995
*/
public abstract class Parser extends Scanner implements Constants {
/**
* Create a parser
*/
protected Parser(Environment env, InputStream in) throws IOException {
super(env, in);
}
/**
* Return the type name associated with a type identifier
*/
protected abstract Identifier resolveClass(Identifier id);
/**
* package declaration
*/
protected abstract void packageDeclaration(int off, Identifier nm);
/**
* import class
*/
protected abstract void importClass(int off, Identifier nm);
/**
* import package
*/
protected abstract void importPackage(int off, Identifier nm);
/**
* Define class
*/
protected abstract void beginClass(int off, String doc, int mod, Identifier nm,
Identifier sup, Identifier impl[]);
/**
* End class
*/
protected abstract void endClass(int off, Identifier nm);
/**
* Define a field
*/
protected abstract void defineField(int where, String doc, int mod, Type t,
Identifier nm, Identifier args[],
Identifier exp[], Node val);
/*
* 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.
*/
private Node args[] = new Node[32];
private int argIndex = 0;
protected final void addArgument(Node n) {
if (argIndex == args.length) {
Node newArgs[] = new Node[args.length * 2];
System.arraycopy(args, 0, newArgs, 0, args.length);
args = newArgs;
}
args[argIndex++] = n;
}
protected final Expression exprArgs(int index)[] {
Expression e[] = new Expression[argIndex - index];
System.arraycopy(args, index, e, 0, argIndex - index);
argIndex = index;
return e;
}
protected final Statement statArgs(int index)[] {
Statement s[] = new Statement[argIndex - index];
System.arraycopy(args, index, s, 0, argIndex - index);
argIndex = index;
return s;
}
/**
* Expect a token, return its value, scan the next token or
* throw an exception.
*/
protected final void expect(int t) throws SyntaxError, IOException {
if (token != t) {
switch (t) {
case IDENT:
env.error(prevPos, "identifier.expected");
break;
default:
env.error(prevPos, "token.expected", opNames[t]);
break;
}
throw new SyntaxError();
}
scan();
}
/**
* Parse a type expression. Does not parse the []'s.
*/
protected Expression parseTypeExpression() throws SyntaxError, IOException {
switch (token) {
case VOID:
return new TypeExpression(scan(), Type.tVoid);
case BOOLEAN:
return new TypeExpression(scan(), Type.tBoolean);
case BYTE:
return new TypeExpression(scan(), Type.tByte);
case CHAR:
return new TypeExpression(scan(), Type.tChar);
case SHORT:
return new TypeExpression(scan(), Type.tShort);
case INT:
return new TypeExpression(scan(), Type.tInt);
case LONG:
return new TypeExpression(scan(), Type.tLong);
case FLOAT:
return new TypeExpression(scan(), Type.tFloat);
case DOUBLE:
return new TypeExpression(scan(), Type.tDouble);
case IDENT:
Expression e = new IdentifierExpression(pos, idValue);
scan();
while (token == FIELD) {
e = new FieldExpression(scan(), e, idValue);
expect(IDENT);
}
return e;
}
env.error(pos, "type.expected");
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 {
int p = scan();
int i = argIndex;
if (token != RPAREN) {
addArgument(parseExpression());
while (token == COMMA) {
scan();
addArgument(parseExpression());
}
}
expect(RPAREN);
return new MethodExpression(p, e, id, exprArgs(i));
}
/**
* Parse a primary expression.
*/
protected Expression parseTerm() throws SyntaxError, IOException {
switch (token) {
case CHARVAL: {
char v = charValue;
return new CharExpression(scan(), v);
}
case INTVAL: {
int v = intValue;
int q = scan();
if (v < 0 && radix == 10) env.error(q, "overflow");
return new IntExpression(q, v);
}
case LONGVAL: {
long v = longValue;
int q = scan();
if (v < 0 && radix == 10) env.error(q, "overflow");
return new LongExpression(q, v);
}
case FLOATVAL: {
float v = floatValue;
return new FloatExpression(scan(), v);
}
case DOUBLEVAL: {
double v = doubleValue;
return new DoubleExpression(scan(), v);
}
case STRINGVAL: {
String v = stringValue;
return new StringExpression(scan(), v);
}
case IDENT: {
Identifier v = idValue;
int p = scan();
return (token == LPAREN) ?
parseMethodExpression(null, v) : new IdentifierExpression(p, v);
}
case TRUE:
return new BooleanExpression(scan(), true);
case FALSE:
return new BooleanExpression(scan(), false);
case NULL:
return new NullExpression(scan());
case THIS: {
Expression e = new ThisExpression(scan());
return (token == LPAREN) ? parseMethodExpression(e, idInit) : e;
}
case SUPER: {
Expression e = new SuperExpression(scan());
return (token == LPAREN) ? parseMethodExpression(e, idInit) : e;
}
case VOID:
case BOOLEAN:
case BYTE:
case CHAR:
case SHORT:
case INT:
case LONG:
case FLOAT:
case DOUBLE:
return parseTypeExpression();
case ADD: {
int p = scan();
switch (token) {
case INTVAL: {
int v = intValue;
int q = scan();
if (v < 0 && radix == 10) env.error(q, "overflow");
return new IntExpression(q, v);
}
case LONGVAL: {
long v = longValue;
int q = scan();
if (v < 0 && radix == 10) env.error(q, "overflow");
return new LongExpression(q, v);
}
case FLOATVAL: {
float v = floatValue;
return new FloatExpression(scan(), v);
}
case DOUBLEVAL: {
double v = doubleValue;
return new DoubleExpression(scan(), v);
}
}
return new PositiveExpression(p, parseTerm());
}
case SUB: {
int p = scan();
switch (token) {
case INTVAL: {
int v = -intValue;
return new IntExpression(scan(), v);
}
case LONGVAL: {
long v = -longValue;
return new LongExpression(scan(), v);
}
case FLOATVAL: {
float v = -floatValue;
return new FloatExpression(scan(), v);
}
case DOUBLEVAL: {
double v = -doubleValue;
return new DoubleExpression(scan(), v);
}
}
return new NegativeExpression(p, parseTerm());
}
case NOT:
return new NotExpression(scan(), parseTerm());
case BITNOT:
return new BitNotExpression(scan(), parseTerm());
case INC:
return new PreIncExpression(scan(), parseTerm());
case DEC:
return new PreDecExpression(scan(), parseTerm());
case LPAREN: {
// bracketed-expr: (expr)
int p = scan();
Expression e = parseExpression();
expect(RPAREN);
if (e.getOp() == TYPE) {
// cast-expr: (simple-type) expr
return new CastExpression(p, e, parseTerm());
}
switch (token) {
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 INC:
case DEC:
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}
int p = scan();
int i = argIndex;
if (token != RBRACE) {
addArgument(parseExpression());
while (token == COMMA) {
scan();
if (token == RBRACE) {
break;
}
addArgument(parseExpression());
}
}
expect(RBRACE);
return new ArrayExpression(p, exprArgs(i));
}
case NEW: {
int p = scan();
int i = argIndex;
if (token == LPAREN) {
scan();
Expression e = parseExpression();
expect(RPAREN);
env.error(p, "not.supported", "new(...)");
return new NullExpression(p);
}
Expression e = parseTypeExpression();
if (token == LSQBRACKET) {
while (token == LSQBRACKET) {
scan();
addArgument((token != RSQBRACKET) ? parseExpression() : null);
expect(RSQBRACKET);
}
return new NewArrayExpression(p, e, exprArgs(i));
} else {
expect(LPAREN);
if (token != RPAREN) {
addArgument(parseExpression());
while (token == COMMA) {
scan();
addArgument(parseExpression());
}
}
expect(RPAREN);
return new NewInstanceExpression(p, e, exprArgs(i));
}
}
}
// System.err.println("NEAR: " + opNames[token]);
env.error(prevPos, "missing.term");
return new IntExpression(pos, 0);
}
/**
* Parse an expression.
*/
protected Expression parseExpression() throws SyntaxError, IOException {
for (Expression e = parseTerm() ; e != null ; e = e.order()) {
switch (token) {
case LSQBRACKET: {
// index: expr1[expr2]
int p = scan();
Expression index = (token != RSQBRACKET) ? parseExpression() : null;
expect(RSQBRACKET);
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: {
int p = scan();
Identifier id = idValue;
expect(IDENT);
if (token == LPAREN) {
e = parseMethodExpression(e, id);
} else {
e = new FieldExpression(p, e, id);
}
break;
}
case INSTANCEOF:
e = new InstanceOfExpression(scan(), e, parseTerm());
break;
case ADD:
e = new AddExpression(scan(), e, parseTerm());
break;
case SUB:
e = new SubtractExpression(scan(), e, parseTerm());
break;
case MUL:
e = new MultiplyExpression(scan(), e, parseTerm());
break;
case DIV:
e = new DivideExpression(scan(), e, parseTerm());
break;
case REM:
e = new RemainderExpression(scan(), e, parseTerm());
break;
case LSHIFT:
e = new ShiftLeftExpression(scan(), e, parseTerm());
break;
case RSHIFT:
e = new ShiftRightExpression(scan(), e, parseTerm());
break;
case URSHIFT:
e = new UnsignedShiftRightExpression(scan(), e, parseTerm());
break;
case LT:
e = new LessExpression(scan(), e, parseTerm());
break;
case LE:
e = new LessOrEqualExpression(scan(), e, parseTerm());
break;
case GT:
e = new GreaterExpression(scan(), e, parseTerm());
break;
case GE:
e = new GreaterOrEqualExpression(scan(), e, parseTerm());
break;
case EQ:
e = new EqualExpression(scan(), e, parseTerm());
break;
case NE:
e = new NotEqualExpression(scan(), e, parseTerm());
break;
case BITAND:
e = new BitAndExpression(scan(), e, parseTerm());
break;
case BITXOR:
e = new BitXorExpression(scan(), e, parseTerm());
break;
case BITOR:
e = new BitOrExpression(scan(), e, parseTerm());
break;
case AND:
e = new AndExpression(scan(), e, parseTerm());
break;
case OR:
e = new OrExpression(scan(), e, parseTerm());
break;
case ASSIGN:
e = new AssignExpression(scan(), e, parseTerm());
break;
case ASGMUL:
e = new AssignMultiplyExpression(scan(), e, parseTerm());
break;
case ASGDIV:
e = new AssignDivideExpression(scan(), e, parseTerm());
break;
case ASGREM:
e = new AssignRemainderExpression(scan(), e, parseTerm());
break;
case ASGADD:
e = new AssignAddExpression(scan(), e, parseTerm());
break;
case ASGSUB:
e = new AssignSubtractExpression(scan(), e, parseTerm());
break;
case ASGLSHIFT:
e = new AssignShiftLeftExpression(scan(), e, parseTerm());
break;
case ASGRSHIFT:
e = new AssignShiftRightExpression(scan(), e, parseTerm());
break;
case ASGURSHIFT:
e = new AssignUnsignedShiftRightExpression(scan(), e, parseTerm());
break;
case ASGBITAND:
e = new AssignBitAndExpression(scan(), e, parseTerm());
break;
case ASGBITOR:
e = new AssignBitOrExpression(scan(), e, parseTerm());
break;
case ASGBITXOR:
e = new AssignBitXorExpression(scan(), e, parseTerm());
break;
case QUESTIONMARK: {
int p = scan();
Expression t = parseExpression();
expect(COLON);
e = new ConditionalExpression(p, e, t, parseExpression());
break;
}
default:
return e;
}
}
// this return is bogus
return null;
}
/**
* Recover after a syntax error in a statement. This involves
* discarding tokens until EOF or a possible continuation is
* encountered.
*/
protected boolean recoverStatement() throws SyntaxError, IOException {
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
expect(RBRACE);
return false;
case LPAREN:
match(LPAREN, RPAREN);
scan();
break;
case LSQBRACKET:
match(LSQBRACKET, RSQBRACKET);
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.
*/
Statement parseDeclaration(int p, int mod, Expression type) throws SyntaxError, IOException {
int i = argIndex;
if (token == IDENT) {
addArgument(new VarDeclarationStatement(pos, parseExpression()));
while (token == COMMA) {
scan();
addArgument(new VarDeclarationStatement(pos, parseExpression()));
}
}
return new DeclarationStatement(p, mod, type, statArgs(i));
}
/**
* Check if an expression is a legal toplevel expression.
* Only method, inc, dec, and new expression are allowed.
*/
void topLevelExpression(Expression e) {
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;
}
env.error(e.getWhere(), "invalid.expr");
}
/**
* Parse a statement.
*/
protected Statement parseStatement() throws SyntaxError, IOException {
switch (token) {
case SEMICOLON:
return new CompoundStatement(scan(), new Statement[0]);
case LBRACE: {
// compound statement: { stat1 stat2 ... statn }
int p = scan();
int i = argIndex;
while ((token != EOF) && (token != RBRACE)) {
int j = argIndex;
try {
addArgument(parseStatement());
} catch (SyntaxError e) {
argIndex = j;
if (!recoverStatement()) {
throw e;
}
}
}
expect(RBRACE);
return new CompoundStatement(p, statArgs(i));
}
case IF: {
// if-statement: if (expr) stat
// if-statement: if (expr) stat else stat
int p = scan();
expect(LPAREN);
Expression c = parseExpression();
expect(RPAREN);
Statement t = parseStatement();
if (token == ELSE) {
scan();
return new IfStatement(p, c, t, parseStatement());
} else {
return new IfStatement(p, c, t, null);
}
}
case ELSE: {
// else-statement: else stat
env.error(scan(), "else.without.if");
return parseStatement();
}
case FOR: {
// for-statement: for (decl-expr? ; expr? ; expr?) stat
int p = scan();
Statement init = null;
Expression cond = null, inc = null;
expect(LPAREN);
if (token != SEMICOLON) {
int p2 = pos;
Expression e = parseExpression();
if (token == IDENT) {
init = parseDeclaration(p2, 0, e);
} else {
topLevelExpression(e);
while (token == COMMA) {
int p3 = scan();
Expression e2 = parseExpression();
topLevelExpression(e2);
e = new CommaExpression(p3, e, e2);
}
init = new ExpressionStatement(p2, e);
}
}
expect(SEMICOLON);
if (token != SEMICOLON) {
cond = parseExpression();
}
expect(SEMICOLON);
if (token != RPAREN) {
inc = parseExpression();
topLevelExpression(inc);
while (token == COMMA) {
int p2 = scan();
Expression e2 = parseExpression();
topLevelExpression(e2);
inc = new CommaExpression(p2, inc, e2);
}
}
expect(RPAREN);
return new ForStatement(p, init, cond, inc, parseStatement());
}
case WHILE: {
// while-statement: while (expr) stat
int p = scan();
expect(LPAREN);
Expression cond = parseExpression();
expect(RPAREN);
return new WhileStatement(p, cond, parseStatement());
}
case DO: {
// do-statement: do stat while (expr)
int p = scan();
Statement body = parseStatement();
expect(WHILE);
expect(LPAREN);
Expression cond = parseExpression();
expect(RPAREN);
expect(SEMICOLON);
return new DoStatement(p, body, cond);
}
case BREAK: {
// break-statement: break ;
int p = scan();
Identifier label = null;
if (token == IDENT) {
label = idValue;
scan();
}
expect(SEMICOLON);
return new BreakStatement(p, label);
}
case CONTINUE: {
// continue-statement: continue ;
int p = scan();
Identifier label = null;
if (token == IDENT) {
label = idValue;
scan();
}
expect(SEMICOLON);
return new ContinueStatement(p, label);
}
case RETURN: {
// return-statement: return ;
// return-statement: return expr ;
int p = scan();
Expression e = null;
if (token != SEMICOLON) {
e = parseExpression();
}
expect(SEMICOLON);
return new ReturnStatement(p, e);
}
case SWITCH: {
// switch statement: switch ( expr ) stat
int p = scan();
int i = argIndex;
expect(LPAREN);
Expression e = parseExpression();
expect(RPAREN);
expect(LBRACE);
while ((token != EOF) && (token != RBRACE)) {
int j = argIndex;
try {
switch (token) {
case CASE:
// case-statement: case expr:
addArgument(new CaseStatement(scan(), parseExpression()));
expect(COLON);
break;
case DEFAULT:
// default-statement: default:
addArgument(new CaseStatement(scan(), null));
expect(COLON);
break;
default:
addArgument(parseStatement());
break;
}
} catch (SyntaxError ee) {
argIndex = j;
if (!recoverStatement()) {
throw ee;
}
}
}
expect(RBRACE);
return new SwitchStatement(p, e, statArgs(i));
}
case CASE: {
// case-statement: case expr : stat
env.error(pos, "case.without.switch");
while (token == CASE) {
scan();
parseExpression();
expect(COLON);
}
return parseStatement();
}
case DEFAULT: {
// default-statement: default : stat
env.error(pos, "default.without.switch");
scan();
expect(COLON);
return parseStatement();
}
case TRY: {
// try-statement: try stat catch (type-expr ident) stat finally stat
int p = scan();
int i = argIndex;
boolean catches = false;
Statement s = parseStatement();
while (token == CATCH) {
int pp = pos;
expect(CATCH);
expect(LPAREN);
Expression t = parseExpression();
Identifier id = (token == IDENT) ? idValue : null;
expect(IDENT);
// We only catch Throwable's, so this is no longer required
// while (token == LSQBRACKET) {
// t = new ArrayAccessExpression(scan(), t, null);
// expect(RSQBRACKET);
// }
expect(RPAREN);
addArgument(new CatchStatement(pp, t, id, parseStatement()));
catches = true;
}
if (catches)
s = new TryStatement(p, s, statArgs(i));
if (token == FINALLY) {
scan();
return new FinallyStatement(p, s, parseStatement());
} else if (catches) {
return s;
} else {
env.error(pos, "try.without.catch.finally");
return new TryStatement(p, s, null);
}
}
case CATCH: {
// catch-statement: catch (expr ident) stat finally stat
env.error(pos, "catch.without.try");
Statement s;
do {
scan();
expect(LPAREN);
parseExpression();
expect(IDENT);
expect(RPAREN);
s = parseStatement();
} while (token == CATCH);
if (token == FINALLY) {
scan();
s = parseStatement();
}
return s;
}
case FINALLY: {
// finally-statement: finally stat
env.error(pos, "finally.without.try");
scan();
return parseStatement();
}
case THROW: {
// throw-statement: throw expr;
int p = scan();
Expression e = parseExpression();
expect(SEMICOLON);
return new ThrowStatement(p, e);
}
case GOTO: {
int p = scan();
expect(IDENT);
expect(SEMICOLON);
env.error(p, "not.supported", "goto");
return new CompoundStatement(p, new Statement[0]);
}
case SYNCHRONIZED: {
// synchronized-statement: synchronized (expr) stat
int p = scan();
expect(LPAREN);
Expression e = parseExpression();
expect(RPAREN);
return new SynchronizedStatement(p, e, parseStatement());
}
case VOID:
case STATIC:
case PUBLIC:
case PRIVATE:
case INTERFACE:
case CLASS:
case TRANSIENT:
// This is the start of something outside a statement
env.error(pos, "statement.expected");
throw new SyntaxError();
}
int p = pos;
Expression e = parseExpression();
if (token == IDENT) {
// declaration: expr expr
Statement s = parseDeclaration(p, 0, e);
expect(SEMICOLON);
return s;
}
if (token == COLON) {
// label: id: stat
scan();
Statement s = parseStatement();
s.setLabel(env, e);
return s;
}
// it was just an expression...
topLevelExpression(e);
expect(SEMICOLON);
return new ExpressionStatement(p, e);
}
/**
* Parse an identifier. ie: a.b.c returns "a.b.c"
* If star is true then "a.b.*" is allowed.
*/
protected Identifier parseIdentifier(boolean star) throws SyntaxError, IOException {
StringBuffer buf = new StringBuffer(32);
if (token == IDENT) {
buf.append(idValue);
}
expect(IDENT);
while (token == FIELD) {
scan();
if ((token == MUL) && star) {
scan();
buf.append(".*");
break;
}
buf.append('.');
if (token == IDENT) {
buf.append(idValue);
}
expect(IDENT);
}
return Identifier.lookup(buf.toString());
}
/**
* Parse a type expression, this results in a Type.
* It does not parse []'s.
*/
protected Type parseType() throws SyntaxError, IOException {
Type t;
switch (token) {
case IDENT:
t = Type.tClass(resolveClass(parseIdentifier(false)));
break;
case VOID:
scan();
t = Type.tVoid;
break;
case BOOLEAN:
scan();
t = Type.tBoolean;
break;
case BYTE:
scan();
t = Type.tByte;
break;
case CHAR:
scan();
t = Type.tChar;
break;
case SHORT:
scan();
t = Type.tShort;
break;
case INT:
scan();
t = Type.tInt;
break;
case FLOAT:
scan();
t = Type.tFloat;
break;
case LONG:
scan();
t = Type.tLong;
break;
case DOUBLE:
scan();
t = Type.tDouble;
break;
default:
env.error(pos, "type.expected");
throw new SyntaxError();
}
// Parse []'s
while (token == LSQBRACKET) {
scan();
expect(RSQBRACKET);
t = Type.tArray(t);
}
return t;
}
/*
* Dealing with argument lists, I'm not using
* Vector for efficiency.
*/
private int aCount = 0;
private Type aTypes[] = new Type[8];
private Identifier aNames[] = new Identifier[aTypes.length];
private void addArgument(Type t, Identifier nm) {
if (aCount >= aTypes.length) {
Type newATypes[] = new Type[aCount * 2];
System.arraycopy(aTypes, 0, newATypes, 0, aCount);
aTypes = newATypes;
Identifier newANames[] = new Identifier[aCount * 2];
System.arraycopy(aNames, 0, newANames, 0, aCount);
aNames = newANames;
}
aTypes[aCount] = t;
aNames[aCount++] = nm;
}
/**
* Parse a field.
*/
protected void parseField() throws SyntaxError, IOException {
// Empty fields are allowed
if (token == SEMICOLON) {
scan();
return;
}
// Optional doc comment
String doc = docComment;
// The start of the field
int p = pos;
// Parse the modifiers
int mod = 0;
while (true) {
int nextmod = 0;
switch (token) {
case PRIVATE: nextmod = M_PRIVATE; break;
case PUBLIC: nextmod = M_PUBLIC; break;
case PROTECTED: nextmod = M_PROTECTED; break;
case STATIC: nextmod = M_STATIC; break;
case TRANSIENT: nextmod = M_TRANSIENT; break;
case FINAL: nextmod = M_FINAL; break;
case ABSTRACT: nextmod = M_ABSTRACT; break;
case NATIVE: nextmod = M_NATIVE; break;
case VOLATILE: nextmod = M_VOLATILE; break;
case SYNCHRONIZED:nextmod = M_SYNCHRONIZED; break;
}
if (nextmod == 0) {
break;
}
if ((mod & nextmod) != 0) {
env.error(pos, "repeated.modifier");
}
mod |= nextmod;
scan();
}
// Check for static initializer
// ie: static { ... }
if ((mod == M_STATIC) && (token == LBRACE)) {
// static initializer
defineField(p, doc, M_STATIC,
Type.tMethod(Type.tVoid),
idClassInit, null, null,
parseStatement());
return;
}
// Parse the type
p = pos;
Type t = parseType();
Identifier id = null;
// 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:
id = idValue;
p = scan();
break;
case LPAREN:
// It is a constructor
id = idInit;
break;
default:
expect(IDENT);
}
// If the next token is a left-bracket then we
// are dealing with a method, otherwise it is
// a list of variables
if (token == LPAREN) {
// It is a method declaration
scan();
aCount = 0;
if (token != RPAREN) {
// Parse argument type and identifier
Type at = parseType();
Identifier an = idValue;
expect(IDENT);
// Parse optional array specifier, ie: a[][]
while (token == LSQBRACKET) {
scan();
if (token != RSQBRACKET) {
env.error(pos, "array.dim.in.decl");
parseExpression();
}
expect(RSQBRACKET);
at = Type.tArray(at);
}
addArgument(at, an);
// If the next token is a comma then there are
// more arguments
while (token == COMMA) {
// Parse argument type and identifier
scan();
at = parseType();
an = idValue;
expect(IDENT);
// Parse optional array specifier, ie: a[][]
while (token == LSQBRACKET) {
scan();
if (token != RSQBRACKET) {
env.error(pos, "array.dim.in.decl");
parseExpression();
}
expect(RSQBRACKET);
at = Type.tArray(at);
}
addArgument(at, an);
}
}
expect(RPAREN);
// Parse optional array sepecifier, ie: foo()[][]
while (token == LSQBRACKET) {
scan();
if (token != RSQBRACKET) {
env.error(pos, "array.dim.in.decl");
parseExpression();
}
expect(RSQBRACKET);
t = Type.tArray(t);
}
// copy arguments
Type atypes[] = new Type[aCount];
System.arraycopy(aTypes, 0, atypes, 0, aCount);
Identifier anames[] = new Identifier[aCount];
System.arraycopy(aNames, 0, anames, 0, aCount);
// Construct the type signature
t = Type.tMethod(t, atypes);
// Parse and ignore throws clause
Identifier exp[] = null;
if (token == THROWS) {
Vector v = new Vector();
scan();
v.addElement(resolveClass(parseIdentifier(false)));
while (token == COMMA) {
scan();
v.addElement(resolveClass(parseIdentifier(false)));
}
exp = new Identifier[v.size()];
v.copyInto(exp);
}
// Check if it is a method definition or a method declaration
// ie: foo() {...} or foo();
switch (token) {
case LBRACE:
// It is a method definition
defineField(p, doc, mod, t, id, anames, exp, parseStatement());
break;
case SEMICOLON:
scan();
defineField(p, doc, mod, t, id, anames, exp, null);
break;
default:
// really expected a statement body here
if ((mod & (M_NATIVE | M_ABSTRACT)) == 0) {
expect(LBRACE);
} else {
expect(SEMICOLON);
}
}
return;
}
// It is a list of instance variables
while (true) {
p = pos; // get the current position
// parse the array brackets (if any)
// ie: var[][][]
Type vt = t;
while (token == LSQBRACKET) {
scan();
if (token != RSQBRACKET) {
env.error(pos, "array.dim.in.decl");
parseExpression();
}
expect(RSQBRACKET);
vt = Type.tArray(vt);
}
// Parse the optional initializer
Node init = null;
if (token == ASSIGN) {
scan();
init = parseExpression();
}
// Define the variable
defineField(p, doc, mod, vt, id, null, null, init);
// If the next token is a comma, then there is more
if (token != COMMA) {
expect(SEMICOLON);
return;
}
scan();
// The next token must be an identifier
id = idValue;
expect(IDENT);
}
}
/**
* Recover after a syntax error in a field. This involves
* discarding tokens until an EOF or a possible legal
* continutation is encountered.
*/
protected void recoverField(Identifier nm) throws SyntaxError, IOException {
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:
match(LBRACE, RBRACE);
scan();
break;
case LPAREN:
match(LPAREN, RPAREN);
scan();
break;
case LSQBRACKET:
match(LSQBRACKET, RSQBRACKET);
scan();
break;
case RBRACE:
case INTERFACE:
case CLASS:
case IMPORT:
case PACKAGE:
// begin of something outside a class, panic more
endClass(pos, nm);
throw new SyntaxError();
default:
// don't know what to do, skip
scan();
break;
}
}
}
/**
* Parse a class or interface declaration.
*/
protected void parseClass() throws SyntaxError, IOException {
String doc = docComment;
// Parse the modifiers
int mod = 0;
while (true) {
int nextmod = 0;
switch (token) {
case PRIVATE: env.error(pos, "private.class"); scan(); continue;
case PUBLIC: nextmod = M_PUBLIC; break;
case FINAL: nextmod = M_FINAL; break;
case ABSTRACT: nextmod = M_ABSTRACT; break;
}
if (nextmod == 0) {
break;
}
if ((mod & nextmod) != 0) {
env.error(pos, "repeated.modifier");
}
mod |= nextmod;
scan();
}
// Parse class/interface
switch (token) {
case INTERFACE:
scan();
mod |= M_INTERFACE;
break;
case CLASS:
scan();
break;
default:
env.error(pos, "class.expected");
break;
}
// Parse the class name
Identifier nm = idValue;
Vector ext = new Vector();
Vector impl = new Vector();
int p = pos;
expect(IDENT);
// Parse extends clause
if (token == EXTENDS) {
scan();
ext.addElement(resolveClass(parseIdentifier(false)));
while (token == COMMA) {
scan();
ext.addElement(resolveClass(parseIdentifier(false)));
}
}
// Parse implements clause
if (token == IMPLEMENTS) {
scan();
impl.addElement(resolveClass(parseIdentifier(false)));
while (token == COMMA) {
scan();
Identifier intf = resolveClass(parseIdentifier(false));
if (impl.contains(intf)) {
env.error(p, "intf.repeated", intf);
} else {
impl.addElement(intf);
}
}
}
// Decide which is the super class
Identifier sup = null;
if ((mod & M_INTERFACE) != 0) {
if (impl.size() > 0) {
env.error(p, "intf.impl.intf");
}
impl = ext;
} else {
if (ext.size() > 0) {
if (ext.size() > 1) {
env.error(p, "multiple.inherit");
}
sup = (Identifier)ext.elementAt(0);
} else {
sup = idJavaLangObject;
}
}
// Begin a new class
Identifier implids[] = new Identifier[impl.size()];
impl.copyInto(implids);
beginClass(p, doc, mod, nm, sup, implids);
// Parse fields
expect(LBRACE);
while ((token != EOF) && (token != RBRACE)) {
try {
parseField();
} catch (SyntaxError e) {
recoverField(nm);
}
}
expect(RBRACE);
// End the class
endClass(prevPos, nm);
}
/**
* Recover after a syntax error in the file.
* This involves discarding tokens until an EOF
* or a possible legal continuation is encountered.
*/
protected void recoverFile() throws IOException {
while (true) {
switch (token) {
case CLASS:
case INTERFACE:
// Start of a new source file statement, continue
return;
case LBRACE:
match(LBRACE, RBRACE);
scan();
break;
case LPAREN:
match(LPAREN, RPAREN);
scan();
break;
case LSQBRACKET:
match(LSQBRACKET, RSQBRACKET);
scan();
break;
case EOF:
return;
default:
// Don't know what to do, skip
scan();
break;
}
}
}
/**
* Parse an Java file.
*/
public void parseFile() {
try {
try {
if (token == PACKAGE) {
// Package statement
int p = scan();
Identifier id = parseIdentifier(false);
expect(SEMICOLON);
packageDeclaration(p, id);
}
} catch (SyntaxError e) {
recoverFile();
}
while (token == IMPORT) {
try{
// Import statement
int p = scan();
Identifier id = parseIdentifier(true);
expect(SEMICOLON);
if (id.getName().equals(idStar)) {
importPackage(p, id.getQualifier());
} else {
importClass(p, id);
}
} catch (SyntaxError e) {
recoverFile();
}
}
while (token != EOF) {
try {
switch (token) {
case FINAL:
case PUBLIC:
case PRIVATE:
case ABSTRACT:
case CLASS:
case INTERFACE:
// Start of a class
parseClass();
break;
case SEMICOLON:
// Bogus semi colon
scan();
break;
case EOF:
// The end
return;
default:
// Oops
env.error(pos, "toplevel.expected");
throw new SyntaxError();
}
} catch (SyntaxError e) {
recoverFile();
}
}
} catch (IOException e) {
env.error(pos, "io.exception", env.getSource());
return;
}
}
}