/* * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * 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. */ 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 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 */ publicclass Parser extends Scanner implements ParserActions, Constants { /** * Create a parser */ protected Parser(Environment env, InputStream in) throws IOException { super(env, in); this.scanner = this; this.actions = this; } /** * Create a parser, given a scanner. */ protected Parser(Scanner scanner) throws IOException { super(scanner.env); this.scanner = scanner; ((Scanner)this).env = scanner.env; ((Scanner)this).token = scanner.token; ((Scanner)this).pos = scanner.pos; this.actions = this; } /** * Create a parser, given a scanner and the semantic callback. */ public Parser(Scanner scanner, ParserActions actions) throws IOException { this(scanner); this.actions = actions; } /** * 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. */ ParserActions actions; // 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 */ @Deprecated public void packageDeclaration(long off, IdentifierToken nm) { // By default, call the deprecated version. // Any application must override one of the packageDeclaration methods. packageDeclaration(off, nm.id); } /** * @deprecated */ @Deprecated protected void packageDeclaration(long off, Identifier nm) { throw new RuntimeException("beginClass method is abstract"); } /** * import class * @deprecated */ @Deprecated public void importClass(long off, IdentifierToken nm) { // By default, call the deprecated version. // Any application must override one of the packageDeclaration methods. importClass(off, nm.id); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void importClass(long off, Identifier nm) { throw new RuntimeException("importClass method is abstract"); } /** * import package * @deprecated */ @Deprecated public void importPackage(long off, IdentifierToken nm) { // By default, call the deprecated version. // Any application must override one of the importPackage methods. importPackage(off, nm.id); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void importPackage(long off, Identifier nm) { throw new RuntimeException("importPackage method is abstract"); } /** * Define class * @deprecated */ @Deprecated public ClassDefinition beginClass(long off, String doc, int mod, IdentifierToken nm, IdentifierToken sup, IdentifierToken impl[]) { // By default, call the deprecated version. // Any application must override one of the beginClass methods. Identifier supId = (sup == null) ? null : sup.id; Identifier implIds[] = null; if (impl != null) { implIds = new Identifier[impl.length]; for (int i = 0; i < impl.length; i++) { implIds[i] = impl[i].id; } } beginClass(off, doc, mod, nm.id, supId, implIds); return getCurrentClass(); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void beginClass(long off, String doc, int mod, Identifier nm, Identifier sup, Identifier impl[]) { 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(). */ protected ClassDefinition getCurrentClass() { return null; } /** * End class * @deprecated */ @Deprecated public void endClass(long off, ClassDefinition c) { // By default, call the deprecated version. // Any application must override one of the beginClass methods. endClass(off, c.getName().getFlatName().getName()); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void endClass(long off, Identifier nm) { throw new RuntimeException("endClass method is abstract"); } /** * Define a field * @deprecated */ @Deprecated public void defineField(long where, ClassDefinition c, String doc, int mod, Type t, IdentifierToken nm, IdentifierToken args[], IdentifierToken exp[], Node val) { // By default, call the deprecated version. // Any application must override one of the defineField methods. Identifier argIds[] = null; Identifier expIds[] = null; if (args != null) { argIds = new Identifier[args.length]; for (int i = 0; i < args.length; i++) { argIds[i] = args[i].id; } } if (exp != null) { expIds = new Identifier[exp.length]; for (int i = 0; i < exp.length; i++) { expIds[i] = exp[i].id; } } defineField(where, doc, mod, t, nm.id, argIds, expIds, val); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void defineField(long where, String doc, int mod, Type t, Identifier nm, Identifier args[], Identifier exp[], Node val) { 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. */ private Node args[] = new Node[32]; protected 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 void expect(int t) throws SyntaxError, IOException { if (token != t) { switch (t) { case IDENT: env.error(scanner.prevPos, "identifier.expected"); break; default: env.error(scanner.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, scanner.idValue); scan(); while (token == FIELD) { e = new FieldExpression(scan(), e, scanner.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 { long 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 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; expect(LPAREN); if (token != RPAREN) { addArgument(parseExpression()); while (token == COMMA) { scan(); addArgument(parseExpression()); } } expect(RPAREN); ClassDefinition body = null; if (token == LBRACE && !(type instanceof TypeExpression)) { long tp = pos; // x = new Type(arg) { subclass body ... } Identifier superName = FieldExpression.toIdentifier(type); if (superName == null) { env.error(type.getWhere(), "type.expected"); } Vector ext = new Vector(1); Vector impl = new Vector(0); ext.addElement(new IdentifierToken(idNull)); if (token == IMPLEMENTS || token == EXTENDS) { env.error(pos, "anonymous.extends"); parseInheritance(ext, impl); // error recovery } body = parseClassBody(new IdentifierToken(tp, idNull), M_ANONYMOUS | M_LOCAL, EXPR, null, ext, impl, type.getWhere()); } if (outerArg == null && body == null) { return new NewInstanceExpression(p, type, exprArgs(i)); } return new NewInstanceExpression(p, type, exprArgs(i), outerArg, body); } /** * Parse a primary expression. */ protected Expression parseTerm() throws SyntaxError, IOException { switch (token) { case CHARVAL: { char v = scanner.charValue; return new CharExpression(scan(), v); } case INTVAL: { int v = scanner.intValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); return new IntExpression(q, v); } case LONGVAL: { long v = scanner.longValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); 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: { String v = scanner.stringValue; return new StringExpression(scan(), v); } case IDENT: { Identifier v = scanner.idValue; long 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: { long p = scan(); switch (token) { case INTVAL: { int v = scanner.intValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); return new IntExpression(q, v); } case LONGVAL: { long v = scanner.longValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); 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);Lines 1–500 of 2130. Load more
/* * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * 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. */ 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 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 class Parser extends Scanner implements ParserActions, Constants { /** * Create a parser */ protected Parser(Environment env, InputStream in) throws IOException { super(env, in); this.scanner = this; this.actions = this; } /** * Create a parser, given a scanner. */ protected Parser(Scanner scanner) throws IOException { super(scanner.env); this.scanner = scanner; ((Scanner)this).env = scanner.env; ((Scanner)this).token = scanner.token; ((Scanner)this).pos = scanner.pos; this.actions = this; } /** * Create a parser, given a scanner and the semantic callback. */ public Parser(Scanner scanner, ParserActions actions) throws IOException { this(scanner); this.actions = actions; } /** * 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. */ ParserActions actions; // 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 */ @Deprecated public void packageDeclaration(long off, IdentifierToken nm) { // By default, call the deprecated version. // Any application must override one of the packageDeclaration methods. packageDeclaration(off, nm.id); } /** * @deprecated */ @Deprecated protected void packageDeclaration(long off, Identifier nm) { throw new RuntimeException("beginClass method is abstract"); } /** * import class * @deprecated */ @Deprecated public void importClass(long off, IdentifierToken nm) { // By default, call the deprecated version. // Any application must override one of the packageDeclaration methods. importClass(off, nm.id); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void importClass(long off, Identifier nm) { throw new RuntimeException("importClass method is abstract"); } /** * import package * @deprecated */ @Deprecated public void importPackage(long off, IdentifierToken nm) { // By default, call the deprecated version. // Any application must override one of the importPackage methods. importPackage(off, nm.id); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void importPackage(long off, Identifier nm) { throw new RuntimeException("importPackage method is abstract"); } /** * Define class * @deprecated */ @Deprecated public ClassDefinition beginClass(long off, String doc, int mod, IdentifierToken nm, IdentifierToken sup, IdentifierToken impl[]) { // By default, call the deprecated version. // Any application must override one of the beginClass methods. Identifier supId = (sup == null) ? null : sup.id; Identifier implIds[] = null; if (impl != null) { implIds = new Identifier[impl.length]; for (int i = 0; i < impl.length; i++) { implIds[i] = impl[i].id; } } beginClass(off, doc, mod, nm.id, supId, implIds); return getCurrentClass(); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void beginClass(long off, String doc, int mod, Identifier nm, Identifier sup, Identifier impl[]) { 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(). */ protected ClassDefinition getCurrentClass() { return null; } /** * End class * @deprecated */ @Deprecated public void endClass(long off, ClassDefinition c) { // By default, call the deprecated version. // Any application must override one of the beginClass methods. endClass(off, c.getName().getFlatName().getName()); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void endClass(long off, Identifier nm) { throw new RuntimeException("endClass method is abstract"); } /** * Define a field * @deprecated */ @Deprecated public void defineField(long where, ClassDefinition c, String doc, int mod, Type t, IdentifierToken nm, IdentifierToken args[], IdentifierToken exp[], Node val) { // By default, call the deprecated version. // Any application must override one of the defineField methods. Identifier argIds[] = null; Identifier expIds[] = null; if (args != null) { argIds = new Identifier[args.length]; for (int i = 0; i < args.length; i++) { argIds[i] = args[i].id; } } if (exp != null) { expIds = new Identifier[exp.length]; for (int i = 0; i < exp.length; i++) { expIds[i] = exp[i].id; } } defineField(where, doc, mod, t, nm.id, argIds, expIds, val); } /** * @deprecated Use the version with the IdentifierToken arguments. */ @Deprecated protected void defineField(long where, String doc, int mod, Type t, Identifier nm, Identifier args[], Identifier exp[], Node val) { 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. */ private Node args[] = new Node[32]; protected 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 void expect(int t) throws SyntaxError, IOException { if (token != t) { switch (t) { case IDENT: env.error(scanner.prevPos, "identifier.expected"); break; default: env.error(scanner.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, scanner.idValue); scan(); while (token == FIELD) { e = new FieldExpression(scan(), e, scanner.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 { long 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 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; expect(LPAREN); if (token != RPAREN) { addArgument(parseExpression()); while (token == COMMA) { scan(); addArgument(parseExpression()); } } expect(RPAREN); ClassDefinition body = null; if (token == LBRACE && !(type instanceof TypeExpression)) { long tp = pos; // x = new Type(arg) { subclass body ... } Identifier superName = FieldExpression.toIdentifier(type); if (superName == null) { env.error(type.getWhere(), "type.expected"); } Vector ext = new Vector(1); Vector impl = new Vector(0); ext.addElement(new IdentifierToken(idNull)); if (token == IMPLEMENTS || token == EXTENDS) { env.error(pos, "anonymous.extends"); parseInheritance(ext, impl); // error recovery } body = parseClassBody(new IdentifierToken(tp, idNull), M_ANONYMOUS | M_LOCAL, EXPR, null, ext, impl, type.getWhere()); } if (outerArg == null && body == null) { return new NewInstanceExpression(p, type, exprArgs(i)); } return new NewInstanceExpression(p, type, exprArgs(i), outerArg, body); } /** * Parse a primary expression. */ protected Expression parseTerm() throws SyntaxError, IOException { switch (token) { case CHARVAL: { char v = scanner.charValue; return new CharExpression(scan(), v); } case INTVAL: { int v = scanner.intValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); return new IntExpression(q, v); } case LONGVAL: { long v = scanner.longValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); 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: { String v = scanner.stringValue; return new StringExpression(scan(), v); } case IDENT: { Identifier v = scanner.idValue; long 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: { long p = scan(); switch (token) { case INTVAL: { int v = scanner.intValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.int.dec"); return new IntExpression(q, v); } case LONGVAL: { long v = scanner.longValue; long q = scan(); if (v < 0 && radix == 10) env.error(q, "overflow.long.dec"); 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);