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