Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/tools/java/Parser.java
38918 views
/*1* Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.tools.java;2627import sun.tools.tree.*;28import java.io.IOException;29import java.io.InputStream;30import java.util.Enumeration;31import java.util.Vector;3233/**34* This class is used to parse Java statements and expressions.35* The result is a parse tree.<p>36*37* This class implements an operator precedence parser. Errors are38* reported to the Environment object, if the error can't be39* resolved immediately, a SyntaxError exception is thrown.<p>40*41* Error recovery is implemented by catching SyntaxError exceptions42* and discarding input tokens until an input token is reached that43* is possibly a legal continuation.<p>44*45* The parse tree that is constructed represents the input46* exactly (no rewrites to simpler forms). This is important47* if the resulting tree is to be used for code formatting in48* a programming environment. Currently only documentation comments49* are retained.<p>50*51* The parsing algorithm does NOT use any type information. Changes52* in the type system do not affect the structure of the parse tree.53* This restriction does introduce an ambiguity an expression of the54* form: (e1) e2 is assumed to be a cast if e2 does not start with55* an operator. That means that (a) - b is interpreted as subtract56* b from a and not cast negative b to type a. However, if a is a57* simple type (byte, int, ...) then it is assumed to be a cast.<p>58*59* WARNING: The contents of this source file are not part of any60* supported API. Code that depends on them does so at its own risk:61* they are subject to change or removal without notice.62*63* @author Arthur van Hoff64*/6566public67class Parser extends Scanner implements ParserActions, Constants {68/**69* Create a parser70*/71protected Parser(Environment env, InputStream in) throws IOException {72super(env, in);73this.scanner = this;74this.actions = this;75}7677/**78* Create a parser, given a scanner.79*/80protected Parser(Scanner scanner) throws IOException {81super(scanner.env);82this.scanner = scanner;83((Scanner)this).env = scanner.env;84((Scanner)this).token = scanner.token;85((Scanner)this).pos = scanner.pos;86this.actions = this;87}8889/**90* Create a parser, given a scanner and the semantic callback.91*/92public Parser(Scanner scanner, ParserActions actions) throws IOException {93this(scanner);94this.actions = actions;95}9697/**98* Usually <code>this.actions == (ParserActions)this</code>.99* However, a delegate scanner can produce tokens for this parser,100* in which case <code>(Scanner)this</code> is unused,101* except for <code>this.token</code> and <code>this.pos</code>102* instance variables which are filled from the real scanner103* by <code>this.scan()</code> and the constructor.104*/105ParserActions actions;106107// Note: The duplication of methods allows pre-1.1 classes to108// be binary compatible with the new version of the parser,109// which now passes IdentifierTokens to the semantics phase,110// rather than just Identifiers. This change is necessary,111// since the parser is no longer responsible for managing the112// resolution of type names. (That caused the "Vector" bug.)113//114// In a future release, the old "plain-Identifier" methods will115// go away, and the corresponding "IdentifierToken" methods116// may become abstract.117118/**119* package declaration120* @deprecated121*/122@Deprecated123public void packageDeclaration(long off, IdentifierToken nm) {124// By default, call the deprecated version.125// Any application must override one of the packageDeclaration methods.126packageDeclaration(off, nm.id);127}128/**129* @deprecated130*/131@Deprecated132protected void packageDeclaration(long off, Identifier nm) {133throw new RuntimeException("beginClass method is abstract");134}135136/**137* import class138* @deprecated139*/140@Deprecated141public void importClass(long off, IdentifierToken nm) {142// By default, call the deprecated version.143// Any application must override one of the packageDeclaration methods.144importClass(off, nm.id);145}146/**147* @deprecated Use the version with the IdentifierToken arguments.148*/149@Deprecated150protected void importClass(long off, Identifier nm) {151throw new RuntimeException("importClass method is abstract");152}153154/**155* import package156* @deprecated157*/158@Deprecated159public void importPackage(long off, IdentifierToken nm) {160// By default, call the deprecated version.161// Any application must override one of the importPackage methods.162importPackage(off, nm.id);163}164/**165* @deprecated Use the version with the IdentifierToken arguments.166*/167@Deprecated168protected void importPackage(long off, Identifier nm) {169throw new RuntimeException("importPackage method is abstract");170}171172/**173* Define class174* @deprecated175*/176@Deprecated177public ClassDefinition beginClass(long off, String doc,178int mod, IdentifierToken nm,179IdentifierToken sup,180IdentifierToken impl[]) {181// By default, call the deprecated version.182// Any application must override one of the beginClass methods.183Identifier supId = (sup == null) ? null : sup.id;184Identifier implIds[] = null;185if (impl != null) {186implIds = new Identifier[impl.length];187for (int i = 0; i < impl.length; i++) {188implIds[i] = impl[i].id;189}190}191beginClass(off, doc, mod, nm.id, supId, implIds);192return getCurrentClass();193}194/**195* @deprecated Use the version with the IdentifierToken arguments.196*/197@Deprecated198protected void beginClass(long off, String doc, int mod, Identifier nm,199Identifier sup, Identifier impl[]) {200throw new RuntimeException("beginClass method is abstract");201}202203/**204* Report the current class under construction.205* By default, it's a no-op which returns null.206* It may only be called before the corresponding endClass().207*/208protected ClassDefinition getCurrentClass() {209return null;210}211212/**213* End class214* @deprecated215*/216@Deprecated217public void endClass(long off, ClassDefinition c) {218// By default, call the deprecated version.219// Any application must override one of the beginClass methods.220endClass(off, c.getName().getFlatName().getName());221}222/**223* @deprecated Use the version with the IdentifierToken arguments.224*/225@Deprecated226protected void endClass(long off, Identifier nm) {227throw new RuntimeException("endClass method is abstract");228}229230/**231* Define a field232* @deprecated233*/234@Deprecated235public void defineField(long where, ClassDefinition c,236String doc, int mod, Type t,237IdentifierToken nm, IdentifierToken args[],238IdentifierToken exp[], Node val) {239// By default, call the deprecated version.240// Any application must override one of the defineField methods.241Identifier argIds[] = null;242Identifier expIds[] = null;243if (args != null) {244argIds = new Identifier[args.length];245for (int i = 0; i < args.length; i++) {246argIds[i] = args[i].id;247}248}249if (exp != null) {250expIds = new Identifier[exp.length];251for (int i = 0; i < exp.length; i++) {252expIds[i] = exp[i].id;253}254}255defineField(where, doc, mod, t, nm.id, argIds, expIds, val);256}257258/**259* @deprecated Use the version with the IdentifierToken arguments.260*/261@Deprecated262protected void defineField(long where, String doc, int mod, Type t,263Identifier nm, Identifier args[],264Identifier exp[], Node val) {265throw new RuntimeException("defineField method is abstract");266}267268/*269* A growable array of nodes. It is used as a growable270* buffer to hold argument lists and expression lists.271* I'm not using Vector to make it more efficient.272*/273private Node args[] = new Node[32];274protected int argIndex = 0;275276protected final void addArgument(Node n) {277if (argIndex == args.length) {278Node newArgs[] = new Node[args.length * 2];279System.arraycopy(args, 0, newArgs, 0, args.length);280args = newArgs;281}282args[argIndex++] = n;283}284protected final Expression exprArgs(int index)[] {285Expression e[] = new Expression[argIndex - index];286System.arraycopy(args, index, e, 0, argIndex - index);287argIndex = index;288return e;289}290protected final Statement statArgs(int index)[] {291Statement s[] = new Statement[argIndex - index];292System.arraycopy(args, index, s, 0, argIndex - index);293argIndex = index;294return s;295}296297/**298* Expect a token, return its value, scan the next token or299* throw an exception.300*/301protected void expect(int t) throws SyntaxError, IOException {302if (token != t) {303switch (t) {304case IDENT:305env.error(scanner.prevPos, "identifier.expected");306break;307default:308env.error(scanner.prevPos, "token.expected", opNames[t]);309break;310}311throw new SyntaxError();312}313scan();314}315316/**317* Parse a type expression. Does not parse the []'s.318*/319protected Expression parseTypeExpression() throws SyntaxError, IOException {320switch (token) {321case VOID:322return new TypeExpression(scan(), Type.tVoid);323case BOOLEAN:324return new TypeExpression(scan(), Type.tBoolean);325case BYTE:326return new TypeExpression(scan(), Type.tByte);327case CHAR:328return new TypeExpression(scan(), Type.tChar);329case SHORT:330return new TypeExpression(scan(), Type.tShort);331case INT:332return new TypeExpression(scan(), Type.tInt);333case LONG:334return new TypeExpression(scan(), Type.tLong);335case FLOAT:336return new TypeExpression(scan(), Type.tFloat);337case DOUBLE:338return new TypeExpression(scan(), Type.tDouble);339case IDENT:340Expression e = new IdentifierExpression(pos, scanner.idValue);341scan();342while (token == FIELD) {343e = new FieldExpression(scan(), e, scanner.idValue);344expect(IDENT);345}346return e;347}348349env.error(pos, "type.expected");350throw new SyntaxError();351}352353/**354* Parse a method invocation. Should be called when the current355* then is the '(' of the argument list.356*/357protected Expression parseMethodExpression(Expression e, Identifier id) throws SyntaxError, IOException {358long p = scan();359int i = argIndex;360if (token != RPAREN) {361addArgument(parseExpression());362while (token == COMMA) {363scan();364addArgument(parseExpression());365}366}367expect(RPAREN);368return new MethodExpression(p, e, id, exprArgs(i));369}370371/**372* Parse a new instance expression. Should be called when the current373* token is the '(' of the argument list.374*/375protected Expression parseNewInstanceExpression(long p, Expression outerArg, Expression type) throws SyntaxError, IOException {376int i = argIndex;377expect(LPAREN);378if (token != RPAREN) {379addArgument(parseExpression());380while (token == COMMA) {381scan();382addArgument(parseExpression());383}384}385expect(RPAREN);386ClassDefinition body = null;387if (token == LBRACE && !(type instanceof TypeExpression)) {388long tp = pos;389// x = new Type(arg) { subclass body ... }390Identifier superName = FieldExpression.toIdentifier(type);391if (superName == null) {392env.error(type.getWhere(), "type.expected");393}394Vector ext = new Vector(1);395Vector impl = new Vector(0);396ext.addElement(new IdentifierToken(idNull));397if (token == IMPLEMENTS || token == EXTENDS) {398env.error(pos, "anonymous.extends");399parseInheritance(ext, impl); // error recovery400}401body = parseClassBody(new IdentifierToken(tp, idNull),402M_ANONYMOUS | M_LOCAL, EXPR, null,403ext, impl, type.getWhere());404}405if (outerArg == null && body == null) {406return new NewInstanceExpression(p, type, exprArgs(i));407}408return new NewInstanceExpression(p, type, exprArgs(i), outerArg, body);409}410411/**412* Parse a primary expression.413*/414protected Expression parseTerm() throws SyntaxError, IOException {415switch (token) {416case CHARVAL: {417char v = scanner.charValue;418return new CharExpression(scan(), v);419}420case INTVAL: {421int v = scanner.intValue;422long q = scan();423if (v < 0 && radix == 10) env.error(q, "overflow.int.dec");424return new IntExpression(q, v);425}426case LONGVAL: {427long v = scanner.longValue;428long q = scan();429if (v < 0 && radix == 10) env.error(q, "overflow.long.dec");430return new LongExpression(q, v);431}432case FLOATVAL: {433float v = scanner.floatValue;434return new FloatExpression(scan(), v);435}436case DOUBLEVAL: {437double v = scanner.doubleValue;438return new DoubleExpression(scan(), v);439}440case STRINGVAL: {441String v = scanner.stringValue;442return new StringExpression(scan(), v);443}444case IDENT: {445Identifier v = scanner.idValue;446long p = scan();447return (token == LPAREN) ?448parseMethodExpression(null, v) : new IdentifierExpression(p, v);449}450451case TRUE:452return new BooleanExpression(scan(), true);453case FALSE:454return new BooleanExpression(scan(), false);455case NULL:456return new NullExpression(scan());457458case THIS: {459Expression e = new ThisExpression(scan());460return (token == LPAREN) ? parseMethodExpression(e, idInit) : e;461}462case SUPER: {463Expression e = new SuperExpression(scan());464return (token == LPAREN) ? parseMethodExpression(e, idInit) : e;465}466467case VOID:468case BOOLEAN:469case BYTE:470case CHAR:471case SHORT:472case INT:473case LONG:474case FLOAT:475case DOUBLE:476return parseTypeExpression();477478case ADD: {479long p = scan();480switch (token) {481case INTVAL: {482int v = scanner.intValue;483long q = scan();484if (v < 0 && radix == 10) env.error(q, "overflow.int.dec");485return new IntExpression(q, v);486}487case LONGVAL: {488long v = scanner.longValue;489long q = scan();490if (v < 0 && radix == 10) env.error(q, "overflow.long.dec");491return new LongExpression(q, v);492}493case FLOATVAL: {494float v = scanner.floatValue;495return new FloatExpression(scan(), v);496}497case DOUBLEVAL: {498double v = scanner.doubleValue;499return new DoubleExpression(scan(), v);500}501}502return new PositiveExpression(p, parseTerm());503}504case SUB: {505long p = scan();506switch (token) {507case INTVAL: {508int v = -scanner.intValue;509return new IntExpression(scan(), v);510}511case LONGVAL: {512long v = -scanner.longValue;513return new LongExpression(scan(), v);514}515case FLOATVAL: {516float v = -scanner.floatValue;517return new FloatExpression(scan(), v);518}519case DOUBLEVAL: {520double v = -scanner.doubleValue;521return new DoubleExpression(scan(), v);522}523}524return new NegativeExpression(p, parseTerm());525}526case NOT:527return new NotExpression(scan(), parseTerm());528case BITNOT:529return new BitNotExpression(scan(), parseTerm());530case INC:531return new PreIncExpression(scan(), parseTerm());532case DEC:533return new PreDecExpression(scan(), parseTerm());534535case LPAREN: {536// bracketed-expr: (expr)537long p = scan();538Expression e = parseExpression();539expect(RPAREN);540541if (e.getOp() == TYPE) {542// cast-expr: (simple-type) expr543return new CastExpression(p, e, parseTerm());544}545546switch (token) {547548// We handle INC and DEC specially.549// See the discussion in JLS section 15.14.1.550// (Part of fix for 4044502.)551552case INC:553// We know this must be a postfix increment.554return new PostIncExpression(scan(), e);555556case DEC:557// We know this must be a postfix decrement.558return new PostDecExpression(scan(), e);559560case LPAREN:561case CHARVAL:562case INTVAL:563case LONGVAL:564case FLOATVAL:565case DOUBLEVAL:566case STRINGVAL:567case IDENT:568case TRUE:569case FALSE:570case NOT:571case BITNOT:572case THIS:573case SUPER:574case NULL:575case NEW:576// cast-expr: (expr) expr577return new CastExpression(p, e, parseTerm());578}579return new ExprExpression(p, e);580}581582case LBRACE: {583// array initializer: {expr1, expr2, ... exprn}584long p = scan();585int i = argIndex;586if (token != RBRACE) {587addArgument(parseExpression());588while (token == COMMA) {589scan();590if (token == RBRACE) {591break;592}593addArgument(parseExpression());594}595}596expect(RBRACE);597return new ArrayExpression(p, exprArgs(i));598}599600case NEW: {601long p = scan();602int i = argIndex;603604if (token == LPAREN) {605scan();606Expression e = parseExpression();607expect(RPAREN);608env.error(p, "not.supported", "new(...)");609return new NullExpression(p);610}611612Expression e = parseTypeExpression();613614if (token == LSQBRACKET) {615while (token == LSQBRACKET) {616scan();617addArgument((token != RSQBRACKET) ? parseExpression() : null);618expect(RSQBRACKET);619}620Expression[] dims = exprArgs(i);621if (token == LBRACE) {622return new NewArrayExpression(p, e, dims, parseTerm());623}624return new NewArrayExpression(p, e, dims);625} else {626return parseNewInstanceExpression(p, null, e);627}628}629}630631// System.err.println("NEAR: " + opNames[token]);632env.error(scanner.prevPos, "missing.term");633return new IntExpression(pos, 0);634}635636/**637* Parse an expression.638*/639protected Expression parseExpression() throws SyntaxError, IOException {640for (Expression e = parseTerm() ; e != null ; e = e.order()) {641Expression more = parseBinaryExpression(e);642if (more == null)643return e;644e = more;645}646// this return is bogus647return null;648}649650/**651* Given a left-hand term, parse an operator and right-hand term.652*/653protected Expression parseBinaryExpression(Expression e) throws SyntaxError, IOException {654if (e != null) {655switch (token) {656case LSQBRACKET: {657// index: expr1[expr2]658long p = scan();659Expression index = (token != RSQBRACKET) ? parseExpression() : null;660expect(RSQBRACKET);661e = new ArrayAccessExpression(p, e, index);662break;663}664665case INC:666e = new PostIncExpression(scan(), e);667break;668case DEC:669e = new PostDecExpression(scan(), e);670break;671case FIELD: {672long p = scan();673if (token == THIS) {674// class C { class N { ... C.this ... } }675// class C { class N { N(C c){ ... c.this() ... } } }676long q = scan();677if (token == LPAREN) {678e = new ThisExpression(q, e);679e = parseMethodExpression(e, idInit);680} else {681e = new FieldExpression(p, e, idThis);682}683break;684}685if (token == SUPER) {686// class D extends C.N { D(C.N n) { n.super(); } }687// Also, 'C.super', as in:688// class C extends CS { class N { ... C.super.foo ... } }689// class C extends CS { class N { ... C.super.foo() ... } }690long q = scan();691if (token == LPAREN) {692e = new SuperExpression(q, e);693e = parseMethodExpression(e, idInit);694} else {695// We must check elsewhere that this expression696// does not stand alone, but qualifies a member name.697e = new FieldExpression(p, e, idSuper);698}699break;700}701if (token == NEW) {702// new C().new N()703scan();704if (token != IDENT)705expect(IDENT);706e = parseNewInstanceExpression(p, e, parseTypeExpression());707break;708}709if (token == CLASS) {710// just class literals, really711// Class c = C.class;712scan();713e = new FieldExpression(p, e, idClass);714break;715}716Identifier id = scanner.idValue;717expect(IDENT);718if (token == LPAREN) {719e = parseMethodExpression(e, id);720} else {721e = new FieldExpression(p, e, id);722}723break;724}725case INSTANCEOF:726e = new InstanceOfExpression(scan(), e, parseTerm());727break;728case ADD:729e = new AddExpression(scan(), e, parseTerm());730break;731case SUB:732e = new SubtractExpression(scan(), e, parseTerm());733break;734case MUL:735e = new MultiplyExpression(scan(), e, parseTerm());736break;737case DIV:738e = new DivideExpression(scan(), e, parseTerm());739break;740case REM:741e = new RemainderExpression(scan(), e, parseTerm());742break;743case LSHIFT:744e = new ShiftLeftExpression(scan(), e, parseTerm());745break;746case RSHIFT:747e = new ShiftRightExpression(scan(), e, parseTerm());748break;749case URSHIFT:750e = new UnsignedShiftRightExpression(scan(), e, parseTerm());751break;752case LT:753e = new LessExpression(scan(), e, parseTerm());754break;755case LE:756e = new LessOrEqualExpression(scan(), e, parseTerm());757break;758case GT:759e = new GreaterExpression(scan(), e, parseTerm());760break;761case GE:762e = new GreaterOrEqualExpression(scan(), e, parseTerm());763break;764case EQ:765e = new EqualExpression(scan(), e, parseTerm());766break;767case NE:768e = new NotEqualExpression(scan(), e, parseTerm());769break;770case BITAND:771e = new BitAndExpression(scan(), e, parseTerm());772break;773case BITXOR:774e = new BitXorExpression(scan(), e, parseTerm());775break;776case BITOR:777e = new BitOrExpression(scan(), e, parseTerm());778break;779case AND:780e = new AndExpression(scan(), e, parseTerm());781break;782case OR:783e = new OrExpression(scan(), e, parseTerm());784break;785case ASSIGN:786e = new AssignExpression(scan(), e, parseTerm());787break;788case ASGMUL:789e = new AssignMultiplyExpression(scan(), e, parseTerm());790break;791case ASGDIV:792e = new AssignDivideExpression(scan(), e, parseTerm());793break;794case ASGREM:795e = new AssignRemainderExpression(scan(), e, parseTerm());796break;797case ASGADD:798e = new AssignAddExpression(scan(), e, parseTerm());799break;800case ASGSUB:801e = new AssignSubtractExpression(scan(), e, parseTerm());802break;803case ASGLSHIFT:804e = new AssignShiftLeftExpression(scan(), e, parseTerm());805break;806case ASGRSHIFT:807e = new AssignShiftRightExpression(scan(), e, parseTerm());808break;809case ASGURSHIFT:810e = new AssignUnsignedShiftRightExpression(scan(), e, parseTerm());811break;812case ASGBITAND:813e = new AssignBitAndExpression(scan(), e, parseTerm());814break;815case ASGBITOR:816e = new AssignBitOrExpression(scan(), e, parseTerm());817break;818case ASGBITXOR:819e = new AssignBitXorExpression(scan(), e, parseTerm());820break;821case QUESTIONMARK: {822long p = scan();823Expression second = parseExpression();824expect(COLON);825Expression third = parseExpression();826827// The grammar in the JLS does not allow assignment828// expressions as the third part of a ?: expression.829// Even though javac has no trouble parsing this,830// check for this case and signal an error.831// (fix for bug 4092958)832if (third instanceof AssignExpression833|| third instanceof AssignOpExpression) {834env.error(third.getWhere(), "assign.in.conditionalexpr");835}836837e = new ConditionalExpression(p, e, second, third);838break;839}840841default:842return null; // mark end of binary expressions843}844}845return e; // return more binary expression stuff846}847848/**849* Recover after a syntax error in a statement. This involves850* discarding tokens until EOF or a possible continuation is851* encountered.852*/853protected boolean recoverStatement() throws SyntaxError, IOException {854while (true) {855switch (token) {856case EOF:857case RBRACE:858case LBRACE:859case IF:860case FOR:861case WHILE:862case DO:863case TRY:864case CATCH:865case FINALLY:866case BREAK:867case CONTINUE:868case RETURN:869// begin of a statement, return870return true;871872case VOID:873case STATIC:874case PUBLIC:875case PRIVATE:876case SYNCHRONIZED:877case INTERFACE:878case CLASS:879case TRANSIENT:880// begin of something outside a statement, panic some more881expect(RBRACE);882return false;883884case LPAREN:885match(LPAREN, RPAREN);886scan();887break;888889case LSQBRACKET:890match(LSQBRACKET, RSQBRACKET);891scan();892break;893894default:895// don't know what to do, skip896scan();897break;898}899}900}901902/**903* Parse declaration, called after the type expression904* has been parsed and the current token is IDENT.905*/906protected Statement parseDeclaration(long p, int mod, Expression type) throws SyntaxError, IOException {907int i = argIndex;908if (token == IDENT) {909addArgument(new VarDeclarationStatement(pos, parseExpression()));910while (token == COMMA) {911scan();912addArgument(new VarDeclarationStatement(pos, parseExpression()));913}914}915return new DeclarationStatement(p, mod, type, statArgs(i));916}917918/**919* Check if an expression is a legal toplevel expression.920* Only method, inc, dec, and new expression are allowed.921*/922protected void topLevelExpression(Expression e) {923switch (e.getOp()) {924case ASSIGN:925case ASGMUL:926case ASGDIV:927case ASGREM:928case ASGADD:929case ASGSUB:930case ASGLSHIFT:931case ASGRSHIFT:932case ASGURSHIFT:933case ASGBITAND:934case ASGBITOR:935case ASGBITXOR:936case PREINC:937case PREDEC:938case POSTINC:939case POSTDEC:940case METHOD:941case NEWINSTANCE:942return;943}944env.error(e.getWhere(), "invalid.expr");945}946947/**948* Parse a statement.949*/950protected Statement parseStatement() throws SyntaxError, IOException {951switch (token) {952case SEMICOLON:953return new CompoundStatement(scan(), new Statement[0]);954955case LBRACE:956return parseBlockStatement();957958case IF: {959// if-statement: if (expr) stat960// if-statement: if (expr) stat else stat961long p = scan();962963expect(LPAREN);964Expression c = parseExpression();965expect(RPAREN);966Statement t = parseStatement();967if (token == ELSE) {968scan();969return new IfStatement(p, c, t, parseStatement());970} else {971return new IfStatement(p, c, t, null);972}973}974975case ELSE: {976// else-statement: else stat977env.error(scan(), "else.without.if");978return parseStatement();979}980981case FOR: {982// for-statement: for (decl-expr? ; expr? ; expr?) stat983long p = scan();984Statement init = null;985Expression cond = null, inc = null;986987expect(LPAREN);988if (token != SEMICOLON) {989long p2 = pos;990int mod = parseModifiers(M_FINAL);991Expression e = parseExpression();992993if (token == IDENT) {994init = parseDeclaration(p2, mod, e);995} else {996if (mod != 0) {997expect(IDENT); // should have been a declaration998}999topLevelExpression(e);1000while (token == COMMA) {1001long p3 = scan();1002Expression e2 = parseExpression();1003topLevelExpression(e2);1004e = new CommaExpression(p3, e, e2);1005}1006init = new ExpressionStatement(p2, e);1007}1008}1009expect(SEMICOLON);1010if (token != SEMICOLON) {1011cond = parseExpression();1012}1013expect(SEMICOLON);1014if (token != RPAREN) {1015inc = parseExpression();1016topLevelExpression(inc);1017while (token == COMMA) {1018long p2 = scan();1019Expression e2 = parseExpression();1020topLevelExpression(e2);1021inc = new CommaExpression(p2, inc, e2);1022}1023}1024expect(RPAREN);1025return new ForStatement(p, init, cond, inc, parseStatement());1026}10271028case WHILE: {1029// while-statement: while (expr) stat1030long p = scan();10311032expect(LPAREN);1033Expression cond = parseExpression();1034expect(RPAREN);1035return new WhileStatement(p, cond, parseStatement());1036}10371038case DO: {1039// do-statement: do stat while (expr)1040long p = scan();10411042Statement body = parseStatement();1043expect(WHILE);1044expect(LPAREN);1045Expression cond = parseExpression();1046expect(RPAREN);1047expect(SEMICOLON);1048return new DoStatement(p, body, cond);1049}10501051case BREAK: {1052// break-statement: break ;1053long p = scan();1054Identifier label = null;10551056if (token == IDENT) {1057label = scanner.idValue;1058scan();1059}1060expect(SEMICOLON);1061return new BreakStatement(p, label);1062}10631064case CONTINUE: {1065// continue-statement: continue ;1066long p = scan();1067Identifier label = null;10681069if (token == IDENT) {1070label = scanner.idValue;1071scan();1072}1073expect(SEMICOLON);1074return new ContinueStatement(p, label);1075}10761077case RETURN: {1078// return-statement: return ;1079// return-statement: return expr ;1080long p = scan();1081Expression e = null;10821083if (token != SEMICOLON) {1084e = parseExpression();1085}1086expect(SEMICOLON);1087return new ReturnStatement(p, e);1088}10891090case SWITCH: {1091// switch statement: switch ( expr ) stat1092long p = scan();1093int i = argIndex;10941095expect(LPAREN);1096Expression e = parseExpression();1097expect(RPAREN);1098expect(LBRACE);10991100while ((token != EOF) && (token != RBRACE)) {1101int j = argIndex;1102try {1103switch (token) {1104case CASE:1105// case-statement: case expr:1106addArgument(new CaseStatement(scan(), parseExpression()));1107expect(COLON);1108break;11091110case DEFAULT:1111// default-statement: default:1112addArgument(new CaseStatement(scan(), null));1113expect(COLON);1114break;11151116default:1117addArgument(parseStatement());1118break;1119}1120} catch (SyntaxError ee) {1121argIndex = j;1122if (!recoverStatement()) {1123throw ee;1124}1125}1126}1127expect(RBRACE);1128return new SwitchStatement(p, e, statArgs(i));1129}11301131case CASE: {1132// case-statement: case expr : stat1133env.error(pos, "case.without.switch");1134while (token == CASE) {1135scan();1136parseExpression();1137expect(COLON);1138}1139return parseStatement();1140}11411142case DEFAULT: {1143// default-statement: default : stat1144env.error(pos, "default.without.switch");1145scan();1146expect(COLON);1147return parseStatement();1148}11491150case TRY: {1151// try-statement: try stat catch (type-expr ident) stat finally stat1152long p = scan();1153Statement init = null; // try-object specification1154int i = argIndex;1155boolean catches = false;11561157if (false && token == LPAREN) {1158expect(LPAREN);1159long p2 = pos;1160int mod = parseModifiers(M_FINAL);1161Expression e = parseExpression();11621163if (token == IDENT) {1164init = parseDeclaration(p2, mod, e);1165// leave check for try (T x, y) for semantic phase1166} else {1167if (mod != 0) {1168expect(IDENT); // should have been a declaration1169}1170init = new ExpressionStatement(p2, e);1171}1172expect(RPAREN);1173}11741175Statement s = parseBlockStatement();11761177if (init != null) {1178// s = new FinallyStatement(p, init, s, 0);1179}11801181while (token == CATCH) {1182long pp = pos;1183expect(CATCH);1184expect(LPAREN);1185int mod = parseModifiers(M_FINAL);1186Expression t = parseExpression();1187IdentifierToken id = scanner.getIdToken();1188expect(IDENT);1189id.modifiers = mod;1190// We only catch Throwable's, so this is no longer required1191// while (token == LSQBRACKET) {1192// t = new ArrayAccessExpression(scan(), t, null);1193// expect(RSQBRACKET);1194// }1195expect(RPAREN);1196addArgument(new CatchStatement(pp, t, id, parseBlockStatement()));1197catches = true;1198}11991200if (catches)1201s = new TryStatement(p, s, statArgs(i));12021203if (token == FINALLY) {1204scan();1205return new FinallyStatement(p, s, parseBlockStatement());1206} else if (catches || init != null) {1207return s;1208} else {1209env.error(pos, "try.without.catch.finally");1210return new TryStatement(p, s, null);1211}1212}12131214case CATCH: {1215// catch-statement: catch (expr ident) stat finally stat1216env.error(pos, "catch.without.try");12171218Statement s;1219do {1220scan();1221expect(LPAREN);1222parseModifiers(M_FINAL);1223parseExpression();1224expect(IDENT);1225expect(RPAREN);1226s = parseBlockStatement();1227} while (token == CATCH);12281229if (token == FINALLY) {1230scan();1231s = parseBlockStatement();1232}1233return s;1234}12351236case FINALLY: {1237// finally-statement: finally stat1238env.error(pos, "finally.without.try");1239scan();1240return parseBlockStatement();1241}12421243case THROW: {1244// throw-statement: throw expr;1245long p = scan();1246Expression e = parseExpression();1247expect(SEMICOLON);1248return new ThrowStatement(p, e);1249}12501251case GOTO: {1252long p = scan();1253expect(IDENT);1254expect(SEMICOLON);1255env.error(p, "not.supported", "goto");1256return new CompoundStatement(p, new Statement[0]);1257}12581259case SYNCHRONIZED: {1260// synchronized-statement: synchronized (expr) stat1261long p = scan();1262expect(LPAREN);1263Expression e = parseExpression();1264expect(RPAREN);1265return new SynchronizedStatement(p, e, parseBlockStatement());1266}12671268case INTERFACE:1269case CLASS:1270// Inner class.1271return parseLocalClass(0);12721273case CONST:1274case ABSTRACT:1275case FINAL:1276case STRICTFP: {1277// a declaration of some sort1278long p = pos;12791280// A class which is local to a block is not a member, and so1281// cannot be public, private, protected, or static. It is in1282// effect private to the block, since it cannot be used outside1283// its scope.1284//1285// However, any class (if it has a name) can be declared final,1286// abstract, or strictfp.1287int mod = parseModifiers(M_FINAL | M_ABSTRACT1288| M_STRICTFP );12891290switch (token) {1291case INTERFACE:1292case CLASS:1293return parseLocalClass(mod);12941295case BOOLEAN:1296case BYTE:1297case CHAR:1298case SHORT:1299case INT:1300case LONG:1301case FLOAT:1302case DOUBLE:1303case IDENT: {1304if ((mod & (M_ABSTRACT | M_STRICTFP )) != 0) {1305mod &= ~ (M_ABSTRACT | M_STRICTFP );1306expect(CLASS);1307}1308Expression e = parseExpression();1309if (token != IDENT) {1310expect(IDENT);1311}1312// declaration: final expr expr1313Statement s = parseDeclaration(p, mod, e);1314expect(SEMICOLON);1315return s;1316}13171318default:1319env.error(pos, "type.expected");1320throw new SyntaxError();1321}1322}13231324case VOID:1325case STATIC:1326case PUBLIC:1327case PRIVATE:1328case TRANSIENT:1329// This is the start of something outside a statement1330env.error(pos, "statement.expected");1331throw new SyntaxError();1332}13331334long p = pos;1335Expression e = parseExpression();13361337if (token == IDENT) {1338// declaration: expr expr1339Statement s = parseDeclaration(p, 0, e);1340expect(SEMICOLON);1341return s;1342}1343if (token == COLON) {1344// label: id: stat1345scan();1346Statement s = parseStatement();1347s.setLabel(env, e);1348return s;1349}13501351// it was just an expression...1352topLevelExpression(e);1353expect(SEMICOLON);1354return new ExpressionStatement(p, e);1355}13561357protected Statement parseBlockStatement() throws SyntaxError, IOException {1358// compound statement: { stat1 stat2 ... statn }1359if (token != LBRACE) {1360// We're expecting a block statement. But we'll probably do the1361// least damage if we try to parse a normal statement instead.1362env.error(scanner.prevPos, "token.expected", opNames[LBRACE]);1363return parseStatement();1364}1365long p = scan();1366int i = argIndex;1367while ((token != EOF) && (token != RBRACE)) {1368int j = argIndex;1369try {1370addArgument(parseStatement());1371} catch (SyntaxError e) {1372argIndex = j;1373if (!recoverStatement()) {1374throw e;1375}1376}1377}13781379expect(RBRACE);1380return new CompoundStatement(p, statArgs(i));1381}138213831384/**1385* Parse an identifier. ie: a.b.c returns "a.b.c"1386* If star is true then "a.b.*" is allowed.1387* The return value encodes both the identifier and its location.1388*/1389protected IdentifierToken parseName(boolean star) throws SyntaxError, IOException {1390IdentifierToken res = scanner.getIdToken();1391expect(IDENT);13921393if (token != FIELD) {1394return res;1395}13961397StringBuffer buf = new StringBuffer(res.id.toString());13981399while (token == FIELD) {1400scan();1401if ((token == MUL) && star) {1402scan();1403buf.append(".*");1404break;1405}14061407buf.append('.');1408if (token == IDENT) {1409buf.append(scanner.idValue);1410}1411expect(IDENT);1412}14131414res.id = Identifier.lookup(buf.toString());1415return res;1416}1417/**1418* @deprecated1419* @see #parseName1420*/1421@Deprecated1422protected Identifier parseIdentifier(boolean star) throws SyntaxError, IOException {1423return parseName(star).id;1424}14251426/**1427* Parse a type expression, this results in a Type.1428* The parse includes trailing array brackets.1429*/1430protected Type parseType() throws SyntaxError, IOException {1431Type t;14321433switch (token) {1434case IDENT:1435t = Type.tClass(parseName(false).id);1436break;1437case VOID:1438scan();1439t = Type.tVoid;1440break;1441case BOOLEAN:1442scan();1443t = Type.tBoolean;1444break;1445case BYTE:1446scan();1447t = Type.tByte;1448break;1449case CHAR:1450scan();1451t = Type.tChar;1452break;1453case SHORT:1454scan();1455t = Type.tShort;1456break;1457case INT:1458scan();1459t = Type.tInt;1460break;1461case FLOAT:1462scan();1463t = Type.tFloat;1464break;1465case LONG:1466scan();1467t = Type.tLong;1468break;1469case DOUBLE:1470scan();1471t = Type.tDouble;1472break;1473default:1474env.error(pos, "type.expected");1475throw new SyntaxError();1476}1477return parseArrayBrackets(t);1478}14791480/**1481* Parse the tail of a type expression, which might be array brackets.1482* Return the given type, as possibly modified by the suffix.1483*/1484protected Type parseArrayBrackets(Type t) throws SyntaxError, IOException {14851486// Parse []'s1487while (token == LSQBRACKET) {1488scan();1489if (token != RSQBRACKET) {1490env.error(pos, "array.dim.in.decl");1491parseExpression();1492}1493expect(RSQBRACKET);1494t = Type.tArray(t);1495}1496return t;1497}14981499/*1500* Dealing with argument lists, I'm not using1501* Vector for efficiency.1502*/15031504private int aCount = 0;1505private Type aTypes[] = new Type[8];1506private IdentifierToken aNames[] = new IdentifierToken[aTypes.length];15071508private void addArgument(int mod, Type t, IdentifierToken nm) {1509nm.modifiers = mod;1510if (aCount >= aTypes.length) {1511Type newATypes[] = new Type[aCount * 2];1512System.arraycopy(aTypes, 0, newATypes, 0, aCount);1513aTypes = newATypes;1514IdentifierToken newANames[] = new IdentifierToken[aCount * 2];1515System.arraycopy(aNames, 0, newANames, 0, aCount);1516aNames = newANames;1517}1518aTypes[aCount] = t;1519aNames[aCount++] = nm;1520}15211522/**1523* Parse a possibly-empty sequence of modifier keywords.1524* Return the resulting bitmask.1525* Diagnose repeated modifiers, but make no other checks.1526* Only modifiers mentioned in the given bitmask are scanned;1527* an unmatched modifier must be handled by the caller.1528*/1529protected int parseModifiers(int mask) throws IOException {1530int mod = 0;1531while (true) {1532if (token==CONST) {1533// const isn't in java, but handle a common C++ usage gently1534env.error(pos, "not.supported", "const");1535scan();1536}1537int nextmod = 0;1538switch (token) {1539case PRIVATE: nextmod = M_PRIVATE; break;1540case PUBLIC: nextmod = M_PUBLIC; break;1541case PROTECTED: nextmod = M_PROTECTED; break;1542case STATIC: nextmod = M_STATIC; break;1543case TRANSIENT: nextmod = M_TRANSIENT; break;1544case FINAL: nextmod = M_FINAL; break;1545case ABSTRACT: nextmod = M_ABSTRACT; break;1546case NATIVE: nextmod = M_NATIVE; break;1547case VOLATILE: nextmod = M_VOLATILE; break;1548case SYNCHRONIZED: nextmod = M_SYNCHRONIZED; break;1549case STRICTFP: nextmod = M_STRICTFP; break;1550}1551if ((nextmod & mask) == 0) {1552break;1553}1554if ((nextmod & mod) != 0) {1555env.error(pos, "repeated.modifier");1556}1557mod |= nextmod;1558scan();1559}1560return mod;1561}15621563private ClassDefinition curClass;15641565/**1566* Parse a field.1567*/1568protected void parseField() throws SyntaxError, IOException {15691570// Empty fields are not allowed by the JLS but are accepted by1571// the compiler, and much code has come to rely on this. It has1572// been decided that the language will be extended to legitimize them.1573if (token == SEMICOLON) {1574// empty field1575scan();1576return;1577}15781579// Optional doc comment1580String doc = scanner.docComment;15811582// The start of the field1583long p = pos;15841585// Parse the modifiers1586int mod = parseModifiers(MM_FIELD | MM_METHOD);15871588// Check for static initializer1589// ie: static { ... }1590// or an instance initializer (w/o the static).1591if ((mod == (mod & M_STATIC)) && (token == LBRACE)) {1592// static initializer1593actions.defineField(p, curClass, doc, mod,1594Type.tMethod(Type.tVoid),1595new IdentifierToken(idClassInit), null, null,1596parseStatement());1597return;1598}15991600// Check for inner class1601if (token == CLASS || token == INTERFACE) {1602parseNamedClass(mod, CLASS, doc);1603return;1604}16051606// Parse the type1607p = pos;1608Type t = parseType();1609IdentifierToken id = null;16101611// Check that the type is followed by an Identifier1612// (the name of the method or the first variable),1613// otherwise it is a constructor.1614switch (token) {1615case IDENT:1616id = scanner.getIdToken();1617p = scan();1618break;16191620case LPAREN:1621// It is a constructor1622id = new IdentifierToken(idInit);1623if ((mod & M_STRICTFP) != 0)1624env.error(pos, "bad.constructor.modifier");1625break;16261627default:1628expect(IDENT);1629}16301631// If the next token is a left-bracket then we1632// are dealing with a method or constructor, otherwise it is1633// a list of variables1634if (token == LPAREN) {1635// It is a method or constructor declaration1636scan();1637aCount = 0;16381639if (token != RPAREN) {1640// Parse argument type and identifier1641// (arguments (like locals) are allowed to be final)1642int am = parseModifiers(M_FINAL);1643Type at = parseType();1644IdentifierToken an = scanner.getIdToken();1645expect(IDENT);16461647// Parse optional array specifier, ie: a[][]1648at = parseArrayBrackets(at);1649addArgument(am, at, an);16501651// If the next token is a comma then there are1652// more arguments1653while (token == COMMA) {1654// Parse argument type and identifier1655scan();1656am = parseModifiers(M_FINAL);1657at = parseType();1658an = scanner.getIdToken();1659expect(IDENT);16601661// Parse optional array specifier, ie: a[][]1662at = parseArrayBrackets(at);1663addArgument(am, at, an);1664}1665}1666expect(RPAREN);16671668// Parse optional array sepecifier, ie: foo()[][]1669t = parseArrayBrackets(t);16701671// copy arguments1672Type atypes[] = new Type[aCount];1673System.arraycopy(aTypes, 0, atypes, 0, aCount);16741675IdentifierToken anames[] = new IdentifierToken[aCount];1676System.arraycopy(aNames, 0, anames, 0, aCount);16771678// Construct the type signature1679t = Type.tMethod(t, atypes);16801681// Parse and ignore throws clause1682IdentifierToken exp[] = null;1683if (token == THROWS) {1684Vector v = new Vector();1685scan();1686v.addElement(parseName(false));1687while (token == COMMA) {1688scan();1689v.addElement(parseName(false));1690}16911692exp = new IdentifierToken[v.size()];1693v.copyInto(exp);1694}16951696// Check if it is a method definition or a method declaration1697// ie: foo() {...} or foo();1698switch (token) {1699case LBRACE: // It's a method definition17001701// Set the state of FP strictness for the body of the method1702int oldFPstate = FPstate;1703if ((mod & M_STRICTFP)!=0) {1704FPstate = M_STRICTFP;1705} else {1706mod |= FPstate & M_STRICTFP;1707}17081709actions.defineField(p, curClass, doc, mod, t, id,1710anames, exp, parseStatement());17111712FPstate = oldFPstate;17131714break;17151716case SEMICOLON:1717scan();1718actions.defineField(p, curClass, doc, mod, t, id,1719anames, exp, null);1720break;17211722default:1723// really expected a statement body here1724if ((mod & (M_NATIVE | M_ABSTRACT)) == 0) {1725expect(LBRACE);1726} else {1727expect(SEMICOLON);1728}1729}1730return;1731}17321733// It is a list of instance variables1734while (true) {1735p = pos; // get the current position1736// parse the array brackets (if any)1737// ie: var[][][]1738Type vt = parseArrayBrackets(t);17391740// Parse the optional initializer1741Node init = null;1742if (token == ASSIGN) {1743scan();1744init = parseExpression();1745}17461747// Define the variable1748actions.defineField(p, curClass, doc, mod, vt, id,1749null, null, init);17501751// If the next token is a comma, then there is more1752if (token != COMMA) {1753expect(SEMICOLON);1754return;1755}1756scan();17571758// The next token must be an identifier1759id = scanner.getIdToken();1760expect(IDENT);1761}1762}17631764/**1765* Recover after a syntax error in a field. This involves1766* discarding tokens until an EOF or a possible legal1767* continuation is encountered.1768*/1769protected void recoverField(ClassDefinition newClass) throws SyntaxError, IOException {1770while (true) {1771switch (token) {1772case EOF:1773case STATIC:1774case FINAL:1775case PUBLIC:1776case PRIVATE:1777case SYNCHRONIZED:1778case TRANSIENT:17791780case VOID:1781case BOOLEAN:1782case BYTE:1783case CHAR:1784case SHORT:1785case INT:1786case FLOAT:1787case LONG:1788case DOUBLE:1789// possible begin of a field, continue1790return;17911792case LBRACE:1793match(LBRACE, RBRACE);1794scan();1795break;17961797case LPAREN:1798match(LPAREN, RPAREN);1799scan();1800break;18011802case LSQBRACKET:1803match(LSQBRACKET, RSQBRACKET);1804scan();1805break;18061807case RBRACE:1808case INTERFACE:1809case CLASS:1810case IMPORT:1811case PACKAGE:1812// begin of something outside a class, panic more1813actions.endClass(pos, newClass);1814throw new SyntaxError();18151816default:1817// don't know what to do, skip1818scan();1819break;1820}1821}1822}18231824/**1825* Parse a top-level class or interface declaration.1826*/1827protected void parseClass() throws SyntaxError, IOException {1828String doc = scanner.docComment;18291830// Parse the modifiers.1831int mod = parseModifiers(MM_CLASS | MM_MEMBER);18321833parseNamedClass(mod, PACKAGE, doc);1834}18351836// Current strict/default state of floating point. This is1837// set and reset with a stack discipline around methods and named1838// classes. Only M_STRICTFP may be set in this word. try...1839// finally is not needed to protect setting and resetting because1840// there are no error messages based on FPstate.1841private int FPstate = 0;18421843/**1844* Parse a block-local class or interface declaration.1845*/1846protected Statement parseLocalClass(int mod) throws SyntaxError, IOException {1847long p = pos;1848ClassDefinition body = parseNamedClass(M_LOCAL | mod, STAT, null);1849Statement ds[] = {1850new VarDeclarationStatement(p, new LocalMember(body), null)1851};1852Expression type = new TypeExpression(p, body.getType());1853return new DeclarationStatement(p, 0, type, ds);1854}18551856/**1857* Parse a named class or interface declaration,1858* starting at "class" or "interface".1859* @arg ctx Syntactic context of the class, one of {PACKAGE CLASS STAT EXPR}.1860*/1861protected ClassDefinition parseNamedClass(int mod, int ctx, String doc) throws SyntaxError, IOException {1862// Parse class/interface1863switch (token) {1864case INTERFACE:1865scan();1866mod |= M_INTERFACE;1867break;18681869case CLASS:1870scan();1871break;18721873default:1874env.error(pos, "class.expected");1875break;1876}18771878int oldFPstate = FPstate;1879if ((mod & M_STRICTFP)!=0) {1880FPstate = M_STRICTFP;1881} else {1882// The & (...) isn't really necessary here because we do maintain1883// the invariant that FPstate has no extra bits set.1884mod |= FPstate & M_STRICTFP;1885}18861887// Parse the class name1888IdentifierToken nm = scanner.getIdToken();1889long p = pos;1890expect(IDENT);18911892Vector ext = new Vector();1893Vector impl = new Vector();1894parseInheritance(ext, impl);18951896ClassDefinition tmp = parseClassBody(nm, mod, ctx, doc, ext, impl, p);18971898FPstate = oldFPstate;18991900return tmp;1901}19021903protected void parseInheritance(Vector ext, Vector impl) throws SyntaxError, IOException {1904// Parse extends clause1905if (token == EXTENDS) {1906scan();1907ext.addElement(parseName(false));1908while (token == COMMA) {1909scan();1910ext.addElement(parseName(false));1911}1912}19131914// Parse implements clause1915if (token == IMPLEMENTS) {1916scan();1917impl.addElement(parseName(false));1918while (token == COMMA) {1919scan();1920impl.addElement(parseName(false));1921}1922}1923}19241925/**1926* Parse the body of a class or interface declaration,1927* starting at the left brace.1928*/1929protected ClassDefinition parseClassBody(IdentifierToken nm, int mod,1930int ctx, String doc,1931Vector ext, Vector impl, long p1932) throws SyntaxError, IOException {1933// Decide which is the super class1934IdentifierToken sup = null;1935if ((mod & M_INTERFACE) != 0) {1936if (impl.size() > 0) {1937env.error(((IdentifierToken)impl.elementAt(0)).getWhere(),1938"intf.impl.intf");1939}1940impl = ext;1941} else {1942if (ext.size() > 0) {1943if (ext.size() > 1) {1944env.error(((IdentifierToken)ext.elementAt(1)).getWhere(),1945"multiple.inherit");1946}1947sup = (IdentifierToken)ext.elementAt(0);1948}1949}19501951ClassDefinition oldClass = curClass;19521953// Begin a new class1954IdentifierToken implids[] = new IdentifierToken[impl.size()];1955impl.copyInto(implids);1956ClassDefinition newClass =1957actions.beginClass(p, doc, mod, nm, sup, implids);19581959// Parse fields1960expect(LBRACE);1961while ((token != EOF) && (token != RBRACE)) {1962try {1963curClass = newClass;1964parseField();1965} catch (SyntaxError e) {1966recoverField(newClass);1967} finally {1968curClass = oldClass;1969}1970}1971expect(RBRACE);19721973// End the class1974actions.endClass(scanner.prevPos, newClass);1975return newClass;1976}19771978/**1979* Recover after a syntax error in the file.1980* This involves discarding tokens until an EOF1981* or a possible legal continuation is encountered.1982*/1983protected void recoverFile() throws IOException {1984while (true) {1985switch (token) {1986case CLASS:1987case INTERFACE:1988// Start of a new source file statement, continue1989return;19901991case LBRACE:1992match(LBRACE, RBRACE);1993scan();1994break;19951996case LPAREN:1997match(LPAREN, RPAREN);1998scan();1999break;20002001case LSQBRACKET:2002match(LSQBRACKET, RSQBRACKET);2003scan();2004break;20052006case EOF:2007return;20082009default:2010// Don't know what to do, skip2011scan();2012break;2013}2014}2015}20162017/**2018* Parse an Java file.2019*/2020public void parseFile() {2021try {2022try {2023if (token == PACKAGE) {2024// Package statement2025long p = scan();2026IdentifierToken id = parseName(false);2027expect(SEMICOLON);2028actions.packageDeclaration(p, id);2029}2030} catch (SyntaxError e) {2031recoverFile();2032}2033while (token == IMPORT) {2034try{2035// Import statement2036long p = scan();2037IdentifierToken id = parseName(true);2038expect(SEMICOLON);2039if (id.id.getName().equals(idStar)) {2040id.id = id.id.getQualifier();2041actions.importPackage(p, id);2042} else {2043actions.importClass(p, id);2044}2045} catch (SyntaxError e) {2046recoverFile();2047}2048}20492050while (token != EOF) {2051try {2052switch (token) {2053case FINAL:2054case PUBLIC:2055case PRIVATE:2056case ABSTRACT:2057case CLASS:2058case INTERFACE:2059case STRICTFP:2060// Start of a class2061parseClass();2062break;20632064case SEMICOLON:2065// Bogus semicolon.2066// According to the JLS (7.6,19.6), a TypeDeclaration2067// may consist of a single semicolon, however, this2068// usage is discouraged (JLS 7.6). In contrast,2069// a FieldDeclaration may not be empty, and is flagged2070// as an error. See parseField above.2071scan();2072break;20732074case EOF:2075// The end2076return;20772078default:2079// Oops2080env.error(pos, "toplevel.expected");2081throw new SyntaxError();2082}2083} catch (SyntaxError e) {2084recoverFile();2085}2086}2087} catch (IOException e) {2088env.error(pos, "io.exception", env.getSource());2089return;2090}2091}20922093/**2094* Usually <code>this.scanner == (Scanner)this</code>.2095* However, a delegate scanner can produce tokens for this parser,2096* in which case <code>(Scanner)this</code> is unused,2097* except for <code>this.token</code> and <code>this.pos</code>2098* instance variables which are filled from the real scanner2099* by <code>this.scan()</code> and the constructor.2100*/2101protected Scanner scanner;21022103// Design Note: We ought to disinherit Parser from Scanner.2104// We also should split out the interface ParserActions from2105// Parser, and make BatchParser implement ParserActions,2106// not extend Parser. This would split scanning, parsing,2107// and class building into distinct responsibility areas.2108// (Perhaps tree building could be virtualized too.)21092110public long scan() throws IOException {2111if (scanner != this && scanner != null) {2112long result = scanner.scan();2113((Scanner)this).token = scanner.token;2114((Scanner)this).pos = scanner.pos;2115return result;2116}2117return super.scan();2118}21192120public void match(int open, int close) throws IOException {2121if (scanner != this) {2122scanner.match(open, close);2123((Scanner)this).token = scanner.token;2124((Scanner)this).pos = scanner.pos;2125return;2126}2127super.match(open, close);2128}2129}213021312132