1 /*
   2  * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.openjdk.asmtools.jasm;
  24 
  25 import org.openjdk.asmtools.common.Module;
  26 
  27 import java.io.IOException;
  28 import java.util.ArrayList;
  29 import java.util.HashSet;
  30 import java.util.Set;
  31 import java.util.function.BiConsumer;
  32 import java.util.function.Consumer;
  33 
  34 import static org.openjdk.asmtools.jasm.ConstantPool.*;
  35 import static org.openjdk.asmtools.jasm.JasmTokens.Token;
  36 import static org.openjdk.asmtools.jasm.JasmTokens.Token.*;
  37 import static org.openjdk.asmtools.jasm.RuntimeConstants.*;
  38 import static org.openjdk.asmtools.jasm.Tables.*;
  39 
  40 /**
  41  * This class is used to parse Jasm statements and expressions.
  42  * The result is a parse tree.<p>
  43  * <p>
  44  * This class implements an operator precedence parser. Errors are
  45  * reported to the Environment object, if the error can't be
  46  * resolved immediately, a SyntaxError exception is thrown.<p>
  47  * <p>
  48  * Error recovery is implemented by catching Scanner.SyntaxError exceptions
  49  * and discarding input scanner.tokens until an input token is reached that
  50  * is possibly a legal continuation.<p>
  51  * <p>
  52  * The parse tree that is constructed represents the input
  53  * exactly (no rewrites to simpler forms). This is important
  54  * if the resulting tree is to be used for code formatting in
  55  * a programming environment. Currently only documentation comments
  56  * are retained.<p>
  57  * <p>
  58  * A parser owns several components (scanner, constant-parser,
  59  * instruction-parser, annotations-parser) to which it delegates certain
  60  * parsing responsibilities.  This parser contains functions to parse the
  61  * overall form of a class, and any members (fields, methods, inner-classes).
  62  * <p>
  63  * <p>
  64  * Syntax errors, should always be caught inside the
  65  * parser for error recovery.
  66  */
  67 class Parser extends ParseBase {
  68 
  69     /* Parser Fields */
  70     protected ConstantPool pool = null;
  71 
  72     ClassData cd = null;
  73 
  74     CodeAttr curCode;
  75 
  76     private ArrayList<ClassData> clsDataList = new ArrayList<>();
  77     private String pkg = null;
  78     private String pkgPrefix = "";
  79     private ArrayList<AnnotationData> pkgAnnttns = null;
  80     private ArrayList<AnnotationData> clsAnnttns = null;
  81     private ArrayList<AnnotationData> memberAnnttns = null;
  82     private boolean explicitcp = false;
  83     private ModuleAttr moduleAttribute;
  84     private CFVersion currentCFV;
  85     /**
  86      * other parser components
  87      */
  88     private ParserAnnotation annotParser;       // For parsing Annotations
  89     private ParserCP cpParser;                  // for parsing Constants
  90     private ParserInstr instrParser;            // for parsing Instructions
  91 
  92 
  93     /**
  94      * Create a parser
  95      */
  96     protected Parser(Environment sf, CFVersion cfVersion) throws IOException {
  97         super.init(new Scanner(sf), this, sf);
  98         this.currentCFV = cfVersion;
  99         this.annotParser = new ParserAnnotation(scanner, this, env);
 100         this.cpParser = new ParserCP(scanner, this, env);
 101         this.instrParser = new ParserInstr(scanner, this, cpParser, env);
 102     }
 103 
 104     void setDebugFlags(boolean debugScanner, boolean debugMembers,
 105                        boolean debugCP, boolean debugAnnot, boolean debugInstr) {
 106 
 107         enableDebug(debugMembers);
 108         scanner.enableDebug(debugScanner);
 109         cpParser.enableDebug(debugCP);
 110         annotParser.enableDebug(debugAnnot);
 111         instrParser.enableDebug(debugInstr);
 112     }
 113 
 114     String encodeClassString(String classname) {
 115         return "L" + classname + ";";
 116     }
 117 
 118 
 119     /*-------------------------------------------------------- */
 120 
 121     /**
 122      * Parses version in package statements
 123      */
 124 
 125     private void parseVersionPkg() throws IOException {
 126         if (scanner.token == SEMICOLON) {
 127             return;
 128         }
 129         parse_ver:
 130         {
 131             if (scanner.token != Token.VERSION) {
 132                 break parse_ver;
 133             }
 134             scanner.scan();
 135             if (scanner.token != Token.INTVAL) {
 136                 break parse_ver;
 137             }
 138             currentCFV.setMajorVersion((short) scanner.intValue);
 139             scanner.scan();
 140             if (scanner.token != Token.COLON) {
 141                 break parse_ver;
 142             }
 143             scanner.scan();
 144             if (scanner.token != Token.INTVAL) {
 145                 break parse_ver;
 146             }
 147             currentCFV.setMinorVersion((short) scanner.intValue);
 148             scanner.scan();
 149             debugScan("     [Parser.parseVersionPkg]: " + currentCFV.asString());
 150             return;
 151         }
 152         env.error(scanner.pos, "version.expected");
 153         throw new Scanner.SyntaxError();
 154     }
 155 
 156     private void parseVersion() throws IOException {
 157         if (scanner.token == Token.LBRACE) {
 158             return;
 159         }
 160         parse_ver:
 161         {
 162             if (scanner.token != Token.VERSION) {
 163                 break parse_ver;
 164             }
 165             scanner.scan();
 166             if (scanner.token != Token.INTVAL) {
 167                 break parse_ver;
 168             }
 169             cd.cfv.setMajorVersion((short) scanner.intValue);
 170             scanner.scan();
 171             if (scanner.token != Token.COLON) {
 172                 break parse_ver;
 173             }
 174             scanner.scan();
 175             if (scanner.token != Token.INTVAL) {
 176                 break parse_ver;
 177             }
 178             cd.cfv.setMinorVersion((short) scanner.intValue);
 179             scanner.scan();
 180             debugStr("parseVersion: " + cd.cfv.asString());
 181             return;
 182         }
 183         env.error(scanner.pos, "version.expected");
 184         throw new Scanner.SyntaxError();
 185     }
 186 
 187 
 188     /*---------------------------------------------*/
 189 
 190     /**
 191      * Parse an internal name: identifier.
 192      */
 193     String parseIdent() throws Scanner.SyntaxError, IOException {
 194         String v = scanner.idValue;
 195         scanner.expect(Token.IDENT);
 196         return v;
 197     }
 198 
 199     /**
 200      * Parse a local variable
 201      */
 202     void parseLocVarDef() throws Scanner.SyntaxError, IOException {
 203         if (scanner.token == Token.INTVAL) {
 204             int v = scanner.intValue;
 205             scanner.scan();
 206             curCode.LocVarDataDef(v);
 207         } else {
 208             String name = scanner.stringValue, type;
 209             scanner.expect(Token.IDENT);
 210             if (scanner.token == Token.COLON) {
 211                 scanner.scan();
 212                 type = parseIdent();
 213             } else {
 214                 type = "I";                  // TBD
 215             }
 216             curCode.LocVarDataDef(name, pool.FindCellAsciz(type));
 217         }
 218     }
 219 
 220     Argument parseLocVarRef() throws Scanner.SyntaxError, IOException {
 221         if (scanner.token == Token.INTVAL) {
 222             int v = scanner.intValue;
 223             scanner.scan();
 224             return new Argument(v);
 225         } else {
 226             String name = scanner.stringValue;
 227             scanner.expect(Token.IDENT);
 228             return curCode.LocVarDataRef(name);
 229         }
 230     }
 231 
 232     void parseLocVarEnd() throws Scanner.SyntaxError, IOException {
 233         if (scanner.token == Token.INTVAL) {
 234             int v = scanner.intValue;
 235             scanner.scan();
 236             curCode.LocVarDataEnd(v);
 237         } else {
 238             String name = scanner.stringValue;
 239             scanner.expect(Token.IDENT);
 240             curCode.LocVarDataEnd(name);
 241         }
 242     }
 243 
 244     void parseMapItem(DataVector map) throws Scanner.SyntaxError, IOException {
 245         StackMapType itemType = stackMapType(scanner.intValue, null);
 246         ConstType tag = null;
 247         Argument arg = null;
 248         Token ptoken = scanner.token;
 249         int iValue = scanner.intValue;
 250         String sValue = scanner.stringValue;
 251         scanner.scan();
 252         resolve:
 253         {
 254             switch (ptoken) {
 255                 case INTVAL:
 256                     break resolve;
 257                 case CLASS:
 258                     itemType = StackMapType.ITEM_Object;
 259                     tag = ConstType.CONSTANT_CLASS;
 260                     break resolve;
 261                 case CPINDEX:
 262                     itemType = StackMapType.ITEM_Object;
 263                     arg = pool.getCell(iValue);
 264                     break resolve;
 265                 case IDENT:
 266                     itemType = stackMapType(sValue);
 267                     tag = Tables.tag(sValue);
 268                     if (itemType != null) { // itemType OK
 269                         if ((tag != null) // ambiguity: "int," or "int 77,"?
 270                                 && (scanner.token != SEMICOLON)
 271                                 && (scanner.token != COMMA)) {
 272                             itemType = StackMapType.ITEM_Object;
 273                         }
 274                         break resolve;
 275                     } else if (tag != null) { // tag OK
 276                         itemType = StackMapType.ITEM_Object;
 277                         break resolve;
 278                     }
 279             }
 280             // resolution failed:
 281             itemType = StackMapType.ITEM_Bogus;
 282             env.error("itemtype.expected", "<" + ptoken.printValue() + ">");
 283         }
 284         switch (itemType) {
 285             case ITEM_Object:  // followed by CP index
 286                 if (arg == null) {
 287                     arg = pool.FindCell(cpParser.parseConstValue(tag));
 288                 }
 289                 map.addElement(new StackMapData.StackMapItem2(itemType, arg));
 290                 break;
 291             case ITEM_NewObject:  // followed by label
 292                 arg = instrParser.parseLabelRef();
 293                 map.addElement(new StackMapData.StackMapItem2(itemType, arg));
 294                 break;
 295             default:
 296                 map.addElement(new StackMapData.StackMapItem1(itemType));
 297         }
 298     }
 299 
 300     /**
 301      * Parse an external name: CPINDEX, string, or identifier.
 302      */
 303     ConstCell parseName() throws Scanner.SyntaxError, IOException {
 304         debugScan("------- [Parser.parseName]: ");
 305         String v;
 306         switch (scanner.token) {
 307             case CPINDEX: {
 308                 int cpx = scanner.intValue;
 309                 scanner.scan();
 310                 return pool.getCell(cpx);
 311             }
 312             case STRINGVAL:
 313                 v = scanner.stringValue;
 314                 scanner.scan();
 315                 return pool.FindCellAsciz(v);
 316 
 317             // In many cases, Identifiers can correctly have the same
 318             // names as keywords.  We need to allow these.
 319             case OPEN:
 320             case MODULE:
 321             case VARARGS:
 322             case REQUIRES:
 323             case EXPORTS:
 324             case TO:
 325             case USES:
 326             case PROVIDES:
 327             case WITH:
 328             case OPENS:
 329 
 330             case ARRAY_TYPEPATH:
 331             case INNER_TYPE_TYPEPATH:
 332             case WILDCARD_TYPEPATH:
 333             case TYPE_ARGUMENT_TYPEPATH:
 334             case PERMITTEDSUBCLASSES:
 335             case INF:
 336             case NAN:
 337             case COMPONENT:
 338 
 339             case SYNTHETIC:
 340             case DEPRECATED:
 341             case VERSION:
 342             case BITS:
 343             case STACK:
 344             case LOCAL:
 345             case OF:
 346             case INNERCLASS:
 347             case STRICT:
 348             case FIELDREF:
 349             case METHODREF:
 350             case IDENT:
 351             case BRIDGE:
 352             case VALUE:
 353             case PERMITS_VALUE:
 354             case PRIMITIVE:
 355                 v = scanner.idValue;
 356                 scanner.scan();
 357                 return pool.FindCellAsciz(v);
 358             default:
 359                 env.error(scanner.pos, "name.expected", scanner.token);
 360                 throw new Scanner.SyntaxError();
 361         }
 362     }
 363 
 364     /**
 365      * Parses a field or method reference for method handle.
 366      */
 367     ConstCell parseMethodHandle(SubTag subtag) throws Scanner.SyntaxError, IOException {
 368         ConstCell refCell;
 369         final int pos = parser.env.pos;
 370         switch (subtag) {
 371             // If the value of the reference_kind item is
 372             // 1 (REF_getField), 2 (REF_getStatic), 3 (REF_putField)  or 4 (REF_putStatic),
 373             // then the constant_pool entry at that index must be a CONSTANT_Fieldref_info structure (4.4.2)
 374             // representing a field for which a method handle is to be created. jvms-4.4.8-200-C-A
 375             case REF_GETFIELD:
 376             case REF_GETSTATIC:
 377             case REF_PUTFIELD:
 378             case REF_PUTSTATIC:
 379                 refCell = pool.FindCell(cpParser.parseConstValue(ConstType.CONSTANT_FIELD));
 380                 break;
 381             //  If the value of the reference_kind item is
 382             //  5 (REF_invokeVirtual) or 8 (REF_newInvokeSpecial),
 383             //  then the constant_pool entry at that index must be a CONSTANT_Methodref_info structure (4.4.2)
 384             //  representing a class's method or constructor (2.9.1) for which a method handle is to be created.
 385             //  jvms-4.4.8-200-C-B
 386             case REF_INVOKEVIRTUAL:
 387             case REF_NEWINVOKESPECIAL:
 388                 cpParser.setExitImmediately(true);
 389                 refCell = cpParser.parseConstRef(ConstType.CONSTANT_METHOD, ConstType.CONSTANT_INTERFACEMETHOD);
 390                 cpParser.setExitImmediately(false);
 391                 checkReferenceIndex(pos, ConstType.CONSTANT_METHOD, null);
 392                 break;
 393             case REF_INVOKESTATIC:
 394             case REF_INVOKESPECIAL:
 395                 // CODETOOLS-7902333
 396                 // 4.4.8. The CONSTANT_MethodHandle_info Structure
 397                 // reference_index
 398                 // The value of the reference_index item must be a valid index into the constant_pool table.
 399                 // The constant_pool entry at that index must be as follows:
 400                 // If the value of the reference_kind item is 6 (REF_invokeStatic) or 7 (REF_invokeSpecial),
 401                 // then if the class file version number is less than 52.0, the constant_pool entry at that index must be
 402                 // a CONSTANT_Methodref_info structure representing a class's method for which a method handle is to be created;
 403                 // if the class file version number is 52.0 or above, the constant_pool entry at that index must be
 404                 // either a CONSTANT_Methodref_info structure or a CONSTANT_InterfaceMethodref_info structure (4.4.2)
 405                 // representing a class's or interface's method for which a method handle is to be created.
 406                 ConstType ctype01 = ConstType.CONSTANT_METHOD;
 407                 ConstType ctype02 = ConstType.CONSTANT_INTERFACEMETHOD;
 408                 if (this.cd.cfv.major_version() >= 52 && Modifiers.isInterface(this.cd.access)) {
 409                     ctype01 = ConstType.CONSTANT_INTERFACEMETHOD;
 410                     ctype02 = ConstType.CONSTANT_METHOD;
 411                 }
 412                 cpParser.setExitImmediately(true);
 413                 refCell = cpParser.parseConstRef(ctype01, ctype02);
 414                 cpParser.setExitImmediately(false);
 415                 checkReferenceIndex(pos, ctype01, ctype02);
 416                 break;
 417 
 418             case REF_INVOKEINTERFACE:
 419                 cpParser.setExitImmediately(true);
 420                 refCell = cpParser.parseConstRef(ConstType.CONSTANT_INTERFACEMETHOD, ConstType.CONSTANT_METHOD);
 421                 cpParser.setExitImmediately(false);
 422                 checkReferenceIndex(pos, ConstType.CONSTANT_INTERFACEMETHOD, null);
 423                 break;
 424             default:
 425                 // should not reach
 426                 throw new Scanner.SyntaxError();
 427         }
 428         return refCell;
 429     }
 430 
 431     /**
 432      * Check the pair reference_kind:reference_index where reference_kind is any from:
 433      * REF_invokeVirtual, REF_newInvokeSpecial, REF_invokeStatic, REF_invokeSpecial, REF_invokeInterface
 434      * and reference_index is one of [Empty], Method or InterfaceMethod
 435      * There are possible entries:
 436      * ldc Dynamic REF_newInvokeSpecial:InterfaceMethod  LdcConDyTwice."<init>":
 437      * ldc Dynamic REF_invokeInterface:LdcConDyTwice."<init>":
 438      * ldc Dynamic REF_newInvokeSpecial:Method LdcConDyTwice."<init>":
 439      * ldc MethodHandle REF_newInvokeSpecial:InterfaceMethod  LdcConDyTwice."<init>":
 440      * ldc MethodHandle REF_invokeInterface:LdcConDyTwice."<init>":
 441      * ldc MethodHandle REF_newInvokeSpecial:Method LdcConDyTwice."<init>":
 442      * invokedynamic MethodHandle REF_invokeStatic:Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants:
 443      * invokedynamic MethodHandle REF_invokeStatic:java/lang/invoke/StringConcatFactory.makeConcatWithConstants
 444      * ....
 445      * @param position   the position in a source file
 446      * @param defaultTag expected reference_index tag (Method or InterfaceMethod)
 447      * @param defaultTag 2nd expected reference_index tag (Method or InterfaceMethod)
 448      */
 449     private void checkReferenceIndex(int position, ConstType defaultTag, ConstType default2Tag) {
 450         if ( ! scanner.token.in(COLON, SEMICOLON) ) {
 451             if (default2Tag != null) {
 452                 env.error(position, "wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey());
 453             } else {
 454                 env.error(position, "wrong.tag", defaultTag.parseKey());
 455             }
 456             throw new Scanner.SyntaxError().Fatal();
 457         }
 458     }
 459 
 460     /**
 461      * Parses a sub-tag value in method handle.
 462      */
 463     SubTag parseSubtag() throws Scanner.SyntaxError, IOException {
 464         SubTag subtag = null;
 465         switch (scanner.token) {
 466             case IDENT:
 467                 subtag = subtag(scanner.stringValue);
 468                 break;
 469             case INTVAL:
 470                 subtag = subtag(scanner.intValue);
 471                 break;
 472         }
 473         if (subtag == null) {
 474             env.error("subtag.expected");
 475             throw new Scanner.SyntaxError();
 476         }
 477         scanner.scan();
 478         return subtag;
 479     }
 480 
 481     ConstCell parseClassName(boolean uncond) throws Scanner.SyntaxError, IOException {
 482         String v;
 483         switch (scanner.token) {
 484             case CPINDEX: {
 485                 int cpx = scanner.intValue;
 486                 scanner.scan();
 487                 return pool.getCell(cpx);
 488             }
 489             case STRINGVAL:
 490                 v = scanner.stringValue;
 491                 scanner.scan();
 492                 v = prependPackage(v, uncond);
 493                 return pool.FindCellAsciz(v);
 494             // Some identifiers might coincide with token names.
 495             // these should be OK to use as identifier names.
 496             case OPEN:
 497             case MODULE:
 498             case VARARGS:
 499             case REQUIRES:
 500             case EXPORTS:
 501             case TO:
 502             case USES:
 503             case PROVIDES:
 504             case WITH:
 505             case OPENS:
 506 
 507             case ARRAY_TYPEPATH:
 508             case INNER_TYPE_TYPEPATH:
 509             case WILDCARD_TYPEPATH:
 510             case TYPE_ARGUMENT_TYPEPATH:
 511             case PERMITTEDSUBCLASSES:
 512             case INF:
 513             case NAN:
 514             case COMPONENT:
 515 
 516             case SYNTHETIC:
 517             case DEPRECATED:
 518             case VERSION:
 519             case BITS:
 520             case STACK:
 521             case LOCAL:
 522             case OF:
 523             case INNERCLASS:
 524             case STRICT:
 525             case FIELDREF:
 526             case METHODREF:
 527             case BRIDGE:
 528             case IDENT:
 529             case VALUE:
 530             case PERMITS_VALUE:
 531             case PRIMITIVE:
 532                 v = scanner.idValue;
 533                 scanner.scan();
 534                 v = prependPackage(v, uncond);
 535                 return pool.FindCellAsciz(v);
 536             default:
 537                 ConstType key = Tables.tag(scanner.token.value());
 538                 env.traceln("%%%%% Unrecognized token [" + scanner.token + "]: '" + (key == null ? "null" : key.parseKey()) + "'.");
 539                 env.error(scanner.prevPos, "name.expected", "\"" + scanner.token.parseKey() + "\"");
 540                 throw new Scanner.SyntaxError();
 541         }
 542     }
 543 
 544     private String prependPackage(String className, boolean uncond) {
 545         if (uncond || (scanner.token == Token.FIELD)) {
 546             if ((!className.contains("/"))             // class identifier doesn't contain "/"
 547                     && (!className.contains("["))) {    // class identifier doesn't contain "["
 548                 className = pkgPrefix + className; // add package
 549             }
 550         }
 551         return className;
 552     }
 553 
 554     /**
 555      * Parse a signed integer of size bytes long.
 556      * size = 1 or 2
 557      */
 558     Argument parseInt(int size) throws Scanner.SyntaxError, IOException {
 559         if (scanner.token == Token.BITS) {
 560             scanner.scan();
 561         }
 562         if (scanner.token != Token.INTVAL) {
 563             env.error(scanner.pos, "int.expected");
 564             throw new Scanner.SyntaxError();
 565         }
 566         int arg = scanner.intValue * scanner.sign;
 567         switch (size) {
 568             case 1:
 569 //                if ((arg>127)||(arg<-128)) { // 0xFF not allowed
 570                 if ((arg > 255) || (arg < -128)) { // to allow 0xFF
 571                     env.error(scanner.pos, "value.large", "1 byte");
 572                     throw new Scanner.SyntaxError();
 573                 }
 574                 break;
 575             case 2:
 576 //                if ((arg > 32767) || (arg < -32768)) { //this seems
 577 // natural but is not backward compatible. Some tests contain
 578 // expressions like:
 579 //                sipush    0x8765;
 580 
 581                 if ((arg > 65535) || (arg < -32768)) {
 582                     env.error(scanner.pos, "value.large", "2 bytes");
 583                     throw new Scanner.SyntaxError();
 584                 }
 585                 break;
 586             default:
 587                 throw new InternalError("parseInt(" + size + ")");
 588         }
 589         scanner.scan();
 590         return new Argument(arg);
 591     }
 592 
 593     /**
 594      * Parse an unsigned integer of size bytes long.
 595      * size = 1 or 2
 596      */
 597     Argument parseUInt(int size) throws Scanner.SyntaxError, IOException {
 598         if (scanner.token != Token.INTVAL) {
 599             env.error(scanner.pos, "int.expected");
 600             throw new Scanner.SyntaxError();
 601         }
 602         if (scanner.sign == -1) {
 603             env.error(scanner.pos, "neg.forbidden");
 604             throw new Scanner.SyntaxError();
 605         }
 606         int arg = scanner.intValue;
 607         switch (size) {
 608             case 1:
 609                 if (arg > 255) {
 610                     env.error(scanner.pos, "value.large", "1 byte");
 611                     throw new Scanner.SyntaxError();
 612                 }
 613                 break;
 614             case 2:
 615                 if (arg > 65535) {
 616                     env.error(scanner.pos, "value.large", "2 bytes");
 617                     throw new Scanner.SyntaxError();
 618                 }
 619                 break;
 620             default:
 621                 throw new InternalError("parseUInt(" + size + ")");
 622         }
 623         scanner.scan();
 624         return new Argument(arg);
 625     }
 626 
 627     /**
 628      * Parse constant declaration
 629      */
 630     private void parseConstDef() throws IOException {
 631         for (; ; ) {
 632             if (scanner.token == Token.CPINDEX) {
 633                 int cpx = scanner.intValue;
 634                 scanner.scan();
 635                 scanner.expect(Token.ASSIGN);
 636                 env.traceln("parseConstDef:" + cpx);
 637                 pool.setCell(cpx, cpParser.parseConstRef(null));
 638             } else {
 639                 env.error("const.def.expected");
 640                 throw new Scanner.SyntaxError();
 641             }
 642             if (scanner.token != COMMA) {
 643                 scanner.expect(SEMICOLON);
 644                 return;
 645             }
 646             scanner.scan(); // COMMA
 647         }
 648     }
 649 
 650     /**
 651      * Parse the modifiers
 652      */
 653     private int scanModifier(int mod) throws IOException {
 654         int nextmod, prevpos;
 655 
 656         while (true) {
 657             nextmod = 0;
 658             switch (scanner.token) {
 659                 case PUBLIC:
 660                     nextmod = ACC_PUBLIC;
 661                     break;
 662                 case PRIVATE:
 663                     nextmod = ACC_PRIVATE;
 664                     break;
 665                 case PROTECTED:
 666                     nextmod = ACC_PROTECTED;
 667                     break;
 668                 case STATIC:
 669                     nextmod = ACC_STATIC;
 670                     break;
 671                 case FINAL:
 672                     nextmod = ACC_FINAL;
 673                     break;
 674                 case SYNCHRONIZED:
 675                     nextmod = ACC_SYNCHRONIZED;
 676                     break;
 677                 case SUPER:
 678                     nextmod = ACC_SUPER;
 679                     break;
 680                 case VOLATILE:
 681                     nextmod = ACC_VOLATILE;
 682                     break;
 683                 case BRIDGE:
 684                     nextmod = ACC_BRIDGE;
 685                     break;
 686                 case TRANSIENT:
 687                     nextmod = ACC_TRANSIENT;
 688                     break;
 689                 case VARARGS:
 690                     nextmod = ACC_VARARGS;
 691                     break;
 692                 case NATIVE:
 693                     nextmod = ACC_NATIVE;
 694                     break;
 695                 case INTERFACE:
 696                     nextmod = ACC_INTERFACE;
 697                     break;
 698                 case ABSTRACT:
 699                     nextmod = ACC_ABSTRACT;
 700                     break;
 701                 case STRICT:
 702                     nextmod = ACC_STRICT;
 703                     break;
 704                 case ENUM:
 705                     nextmod = ACC_ENUM;
 706                     break;
 707                 case SYNTHETIC:
 708                     nextmod = ACC_SYNTHETIC;
 709                     break;
 710                 case ANNOTATION_ACCESS:
 711                     nextmod = ACC_ANNOTATION;
 712                     break;
 713 
 714                 case DEPRECATED:
 715                     nextmod = DEPRECATED_ATTRIBUTE;
 716                     break;
 717                 case MANDATED:
 718                     nextmod = ACC_MANDATED;
 719                     break;
 720                 case VALUE:
 721                     nextmod = ACC_VALUE;
 722                     break;
 723                 case PERMITS_VALUE:
 724                     nextmod = ACC_PERMITS_VALUE;
 725                     break;
 726                 case PRIMITIVE:
 727                     nextmod = ACC_PRIMITIVE;
 728                     break;
 729                 default:
 730                     return nextmod;
 731             }
 732             prevpos = scanner.pos;
 733             scanner.scan();
 734             if ((mod & nextmod) == 0) {
 735                 return nextmod;
 736             }
 737             env.error(prevpos, "warn.repeated.modifier");
 738         }
 739     }
 740 
 741     int scanModifiers() throws IOException {
 742         int mod = 0, nextmod;
 743 
 744         while (true) {
 745             nextmod = scanModifier(mod);
 746             if (nextmod == 0) {
 747                 return mod;
 748             }
 749             mod = mod | nextmod;
 750         }
 751     }
 752 
 753     /**
 754      * Parse a field.
 755      */
 756     private void parseField(int mod) throws Scanner.SyntaxError, IOException {
 757         debugStr("  [Parser.parseField]: <<<Begin>>>");
 758         // check access modifiers:
 759         Modifiers.checkFieldModifiers(cd, mod, scanner.pos);
 760 
 761         while (true) {
 762             ConstCell nameCell = parseName();
 763             scanner.expect(Token.COLON);
 764             ConstCell typeCell = parseName();
 765 
 766             // Define the variable
 767             FieldData fld = cd.addField(mod, nameCell, typeCell);
 768 
 769             if (memberAnnttns != null) {
 770                 fld.addAnnotations(memberAnnttns);
 771             }
 772 
 773             // Parse the optional attribute: signature
 774             if (scanner.token == Token.COLON) {
 775                 scanner.scan();
 776                 ConstCell signatureCell = parseName();
 777                 fld.setSignatureAttr(signatureCell);
 778             }
 779 
 780             // Parse the optional initializer
 781             if (scanner.token == Token.ASSIGN) {
 782                 scanner.scan();
 783                 fld.SetValue(cpParser.parseConstRef(null));
 784             }
 785 
 786             // If the next scanner.token is a comma, then there is more
 787             debugScan("  [Parser.parseField]: Field: " + fld + " ");
 788 
 789             if (scanner.token != COMMA) {
 790                 scanner.expect(SEMICOLON);
 791                 return;
 792             }
 793             scanner.scan();
 794         }  // end while
 795     }  // end parseField
 796 
 797     /**
 798      * Scan method's signature to determine size of parameters.
 799      */
 800     private int countParams(ConstCell sigCell) throws Scanner.SyntaxError {
 801         String sig;
 802         try {
 803             ConstValue_String strConst = (ConstValue_String) sigCell.ref;
 804             sig = strConst.value;
 805         } catch (NullPointerException | ClassCastException e) {
 806             return 0; // ??? TBD
 807         }
 808         int siglen = sig.length(), k = 0, loccnt = 0, errparam = 0;
 809         boolean arraytype = false;
 810         scan:
 811         {
 812             if (k >= siglen) {
 813                 break scan;
 814             }
 815             if (sig.charAt(k) != '(') {
 816                 errparam = 1;
 817                 break scan;
 818             }
 819             for (k = 1; k < siglen; k++) {
 820                 switch (sig.charAt(k)) {
 821                     case ')':
 822                         if (arraytype) {
 823                             errparam = 2;
 824                             break scan;
 825                         }
 826                         return loccnt;
 827                     case '[':
 828                         arraytype = true;
 829                         break;
 830                     case 'B':
 831                     case 'C':
 832                     case 'F':
 833                     case 'I':
 834                     case 'S':
 835                     case 'Z':
 836                         loccnt++;
 837                         arraytype = false;
 838                         break;
 839                     case 'D':
 840                     case 'J':
 841                         loccnt++;
 842                         if (arraytype) {
 843                             arraytype = false;
 844                         } else {
 845                             loccnt++;
 846                         }
 847                         break;
 848                     case 'L':
 849                     case 'Q':
 850                         for (; ; k++) {
 851                             if (k >= siglen) {
 852                                 errparam = 3;
 853                                 break scan;
 854                             }
 855                             if (sig.charAt(k) == ';') {
 856                                 break;
 857                             }
 858                         }
 859                         loccnt++;
 860                         arraytype = false;
 861                         break;
 862                     default:
 863                         errparam = 4;
 864                         break scan;
 865                 }
 866             }
 867         }
 868         env.error(scanner.pos, "msig.malformed", Integer.toString(k), Integer.toString(errparam));
 869         return loccnt;
 870     }
 871 
 872     /**
 873      * Parse a method.
 874      */
 875     private void parseMethod(int mod) throws Scanner.SyntaxError, IOException {
 876 
 877         // The start of the method
 878         int posa = scanner.pos;
 879         debugStr("  [Parser.parseMethod]: <<<Begin>>>");
 880 
 881         ConstCell nameCell = parseName();
 882         ConstValue_String strConst = (ConstValue_String) nameCell.ref;
 883         String name = strConst.value;
 884         boolean is_clinit = name.equals("<clinit>");
 885         boolean is_init = name.equals("<init>")
 886             && !Modifiers.isStatic(mod); // TODO: not a good way to detect factories...
 887         DefaultAnnotationAttr defAnnot = null;
 888 
 889         // check access modifiers:
 890         Modifiers.checkMethodModifiers(cd, mod, posa, is_init, is_clinit);
 891 
 892         scanner.expect(Token.COLON);
 893         ConstCell typeCell = parseName();
 894         int paramcnt = countParams(typeCell);
 895         if ((!Modifiers.isStatic(mod)) && !is_clinit) {
 896             paramcnt++;
 897         }
 898         if (paramcnt > 255) {
 899             env.error(scanner.pos, "warn.msig.more255", Integer.toString(paramcnt));
 900         }
 901         // Parse throws clause
 902         ArrayList<ConstCell> exc_table = null;
 903         if (scanner.token == Token.THROWS) {
 904             scanner.scan();
 905             exc_table = new ArrayList<>();
 906             for (; ; ) {
 907                 posa = scanner.pos;
 908                 ConstCell exc = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
 909                 if (exc_table.contains(exc)) {
 910                     env.error(posa, "warn.exc.repeated");
 911                 } else {
 912                     exc_table.add(exc);
 913                     env.traceln("THROWS:" + exc.arg);
 914                 }
 915                 if (scanner.token != COMMA) {
 916                     break;
 917                 }
 918                 scanner.scan();
 919             }
 920         }
 921         if (scanner.token == Token.DEFAULT) {
 922             // need to scan the annotation value
 923             defAnnot = annotParser.parseDefaultAnnotation();
 924         }
 925 
 926         MethodData curMethod = cd.StartMethod(mod, nameCell, typeCell, exc_table);
 927         Argument max_stack = null, max_locals = null;
 928 
 929         if (scanner.token == Token.STACK) {
 930             scanner.scan();
 931             max_stack = parseUInt(2);
 932         }
 933         if (scanner.token == Token.LOCAL) {
 934             scanner.scan();
 935             max_locals = parseUInt(2);
 936         }
 937         if (scanner.token == Token.INTVAL) {
 938             annotParser.parseParamAnnots(paramcnt, curMethod);
 939         }
 940 
 941         if (scanner.token == SEMICOLON) {
 942             if ((max_stack != null) || (max_locals != null)) {
 943                 env.error("token.expected", "{");
 944             }
 945             scanner.scan();
 946         } else {
 947             scanner.expect(Token.LBRACE);
 948             curCode = curMethod.startCode(posa, paramcnt, max_stack, max_locals);
 949             while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) {
 950                 instrParser.parseInstr();
 951                 if (scanner.token == Token.RBRACE) {
 952                     break;
 953                 }
 954                 // code's type annotation(s)
 955                 if (scanner.token == Token.ANNOTATION) {
 956                     curCode.addAnnotations(annotParser.scanAnnotations());
 957                     break;
 958                 }
 959                 scanner.expect(SEMICOLON);
 960             }
 961             curCode.endCode();
 962             scanner.expect(Token.RBRACE);
 963         }
 964 
 965         if (defAnnot != null) {
 966             curMethod.addDefaultAnnotation(defAnnot);
 967         }
 968         if (memberAnnttns != null) {
 969             curMethod.addAnnotations(memberAnnttns);
 970         }
 971         cd.EndMethod();
 972         debugStr("  [Parser.parseMethod]: Method: " + curMethod);
 973 
 974     }  // end parseMethod
 975 
 976     /**
 977      * Parse a (CPX based) BootstrapMethod entry.
 978      */
 979     private void parseCPXBootstrapMethod() throws Scanner.SyntaxError, IOException {
 980         // Parses in the form:
 981         // BOOTSTRAPMETHOD CPX_MethodHandle (CPX_Arg)* ;
 982         if (scanner.token == Token.CPINDEX) {
 983             // CPX can be a CPX to an MethodHandle constant,
 984             int cpx = scanner.intValue;
 985             ConstCell MHCell = pool.getCell(cpx);
 986             scanner.scan();
 987             ArrayList<ConstCell> bsm_args = new ArrayList<>(256);
 988 
 989             while (scanner.token != SEMICOLON) {
 990                 if (scanner.token == Token.CPINDEX) {
 991                     bsm_args.add(pool.getCell(scanner.intValue));
 992 
 993                 } else {
 994                     // throw error, bootstrap method is not recognizable
 995                     env.error(scanner.pos, "invalid.bootstrapmethod");
 996                     throw new Scanner.SyntaxError();
 997                 }
 998                 scanner.scan();
 999             }
1000             BootstrapMethodData bsmData = new BootstrapMethodData(MHCell, bsm_args);
1001             cd.addBootstrapMethod(bsmData);
1002         } else {
1003             // throw error, bootstrap method is not recognizable
1004             env.error(scanner.pos, "invalid.bootstrapmethod");
1005             throw new Scanner.SyntaxError();
1006         }
1007     }
1008 
1009     /**
1010      * Parse a NestHost entry
1011      */
1012     private void parseNestHost() throws Scanner.SyntaxError, IOException {
1013         // Parses in the form:
1014         // NESTHOST IDENT;
1015         debugStr("  [Parser.parseNestHost]: <<<Begin>>>");
1016         String className = prependPackage(parseIdent(), true);
1017         ConstCell hostClass = pool.FindCellClassByName(className);
1018         debugScan("  [Parser.parseNestHost]: NestHost: class " + className);
1019         scanner.expect(SEMICOLON);
1020         cd.addNestHost(hostClass);
1021     }
1022 
1023     /**
1024      * Parse a list of classes belonging to the
1025      * [NestMembers | PermittedSubclasses | Preload]  entry
1026      */
1027     private void parseClasses(Consumer<ArrayList<ConstCell>> classesConsumer)
1028             throws Scanner.SyntaxError, IOException {
1029         ArrayList<ConstCell> classes = new ArrayList<>();
1030         // Parses in the form:
1031         // (NESTMEMBERS|PERMITTEDSUBCLASSES)? IDENT(, IDENT)*;
1032         debugStr("  [Parser.parseClasses]: <<<Begin>>>");
1033         while (true) {
1034             String className = prependPackage(parseIdent(), true);
1035             classes.add(pool.FindCellClassByName(className));
1036             debugScan("  [Parser.parseClasses]: class " + className);
1037             if (scanner.token != COMMA) {
1038                 scanner.expect(SEMICOLON);
1039                 classesConsumer.accept(classes);
1040                 return;
1041             }
1042             scanner.scan();
1043         }
1044     }
1045 
1046     /**
1047      * Parse the Record entry
1048      */
1049     private void parseRecord() throws Scanner.SyntaxError, IOException {
1050         // Parses in the form:
1051         // RECORD { (COMPONENT)+ }
1052         // where
1053         // COMPONENT Component (ANNOTATION)* NAME:DESCRIPTOR(:SIGNATURE)? (,|;)
1054         // NAME = (CPINDEX | IDENT)
1055         // DESCRIPTOR = (CPINDEX | STRING)
1056         // SIGNATURE  = (CPINDEX | STRING)
1057         debugScan("[Parser.parseRecord]:  Begin");
1058         scanner.expect(Token.LBRACE);
1059 
1060         ArrayList<AnnotationData> componentAnntts = null;
1061         boolean grouped = false;
1062         RecordData rd = cd.setRecord(scanner.pos);
1063 
1064         while (true) {
1065             if (scanner.token == Token.RBRACE) {
1066                 if (rd.isEmpty()) {
1067                     env.error(scanner.pos, "warn.no.components.in.record.attribute");
1068                     cd.rejectRecord();
1069                 } else if (grouped) {
1070                     env.error(scanner.pos, "grouped.component.expected");
1071                 }
1072                 scanner.scan();
1073                 break;
1074             }
1075 
1076             ConstCell nameCell, descCell, signatureCell = null;
1077             if (scanner.token == Token.ANNOTATION) {
1078                 componentAnntts = annotParser.scanAnnotations();
1079             }
1080 
1081             scanner.expect(Token.COMPONENT);
1082 
1083             nameCell = parseName();
1084             scanner.expect(Token.COLON);
1085             descCell = parseName();
1086             // Parse the optional attribute: signature
1087             if (scanner.token == Token.COLON) {
1088                 scanner.scan();
1089                 signatureCell = parseName();
1090             }
1091 
1092             rd.addComponent(nameCell, descCell, signatureCell, componentAnntts);
1093 
1094             switch (scanner.token) {
1095                 case COMMA:
1096                     grouped = true;
1097                     break;
1098                 case SEMICOLON:
1099                     grouped = false;
1100                     componentAnntts = null;
1101                     break;
1102                 default:
1103                     env.error(scanner.pos, "one.of.two.token.expected",
1104                             "<" + SEMICOLON.printValue() + ">",
1105                             "<" + COMMA.printValue() + ">");
1106                     break;
1107             }
1108             // next component
1109             scanner.scan();
1110         }  // end while
1111         debugScan("[Parser.parseRecord]:  End");
1112     }
1113 
1114     /**
1115      * Parse an inner class.
1116      */
1117     private void parseInnerClass(int mod) throws Scanner.SyntaxError, IOException {
1118         // Parses in the form:
1119         // MODIFIERS (INNERCLASSNAME =)? (INNERCLASS) (OF OUTERCLASS)? ;
1120         //
1121         // where
1122         //    INNERCLASSNAME = (IDENT | CPX_IN-CL-NM)
1123         //    INNERCLASS = (CLASS IDENT | CPX_IN-CL) (S2)
1124         //    OUTERCLASS = (CLASS IDENT | CPX_OT-CL) (S3)
1125         //
1126         // Note:
1127         //    If a class reference cannot be identified using IDENT, CPX indexes must be used.
1128 
1129         // check access modifiers:
1130         debugScan("[Parser.parseInnerClass]:  Begin ");
1131         Modifiers.checkInnerClassModifiers(cd, mod, scanner.pos);
1132 
1133         ConstCell nameCell;
1134         ConstCell innerClass = null;
1135         ConstCell outerClass = null;
1136 
1137 
1138         if (scanner.token == Token.CLASS) {
1139             nameCell = pool.getCell(0);  // no NameIndex
1140             parseInnerClass_s2(mod, nameCell, innerClass, outerClass);
1141         } else {
1142             if ((scanner.token == Token.IDENT) || scanner.checkTokenIdent()) {
1143                 // Got a Class Name
1144                 nameCell = parseName();
1145                 parseInnerClass_s1(mod, nameCell, innerClass, outerClass);
1146             } else if (scanner.token == Token.CPINDEX) {
1147                 // CPX can be either a CPX to an InnerClassName,
1148                 // or a CPX to an InnerClassInfo
1149                 int cpx = scanner.intValue;
1150                 nameCell = pool.getCell(cpx);
1151                 ConstValue nameCellValue = nameCell.ref;
1152 
1153                 if (nameCellValue instanceof ConstValue_String) {
1154                     // got a name cell
1155                     scanner.scan();
1156                     parseInnerClass_s1(mod, nameCell, innerClass, outerClass);
1157                 } else {
1158                     // got a CPRef cell
1159                     nameCell = pool.getCell(0);  // no NameIndex
1160                     parseInnerClass_s2(mod, nameCell, innerClass, outerClass);
1161                 }
1162             } else {
1163                 pic_error();
1164             }
1165 
1166         }
1167     }
1168 
1169     private void parseInnerClass_s1(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException {
1170         // next scanner.token must be '='
1171         if (scanner.token == Token.ASSIGN) {
1172             scanner.scan();
1173             parseInnerClass_s2(mod, nameCell, innerClass, outerClass);
1174         } else {
1175             pic_error();
1176         }
1177 
1178     }
1179 
1180     private void parseInnerClass_s2(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException {
1181         // scanner.token is either "CLASS IDENT" or "CPX_Class"
1182         if ((scanner.token == Token.CPINDEX) || (scanner.token == Token.CLASS)) {
1183             if (scanner.token == Token.CPINDEX) {
1184                 innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1185             }
1186 
1187             if (scanner.token == Token.CLASS) {
1188                 // next symbol needs to be InnerClass
1189                 scanner.scan();
1190                 innerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1191             }
1192 
1193             // See if declaration is terminated
1194             if (scanner.token == SEMICOLON) {
1195                 // InnerClass is complete, no OUTERINFO;
1196                 outerClass = pool.getCell(0);
1197                 pic_tracecreate(mod, nameCell, innerClass, outerClass);
1198                 cd.addInnerClass(mod, nameCell, innerClass, outerClass);
1199             } else if (scanner.token == Token.OF) {
1200                 // got an outer class reference
1201                 parseInnerClass_s3(mod, nameCell, innerClass, outerClass);
1202             } else {
1203                 pic_error();
1204             }
1205 
1206         } else {
1207             pic_error();
1208         }
1209 
1210     }
1211 
1212     private void parseInnerClass_s3(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) throws IOException {
1213         scanner.scan();
1214         if ((scanner.token == Token.CLASS) || (scanner.token == Token.CPINDEX)) {
1215             if (scanner.token == Token.CLASS) {
1216                 // next symbol needs to be InnerClass
1217                 scanner.scan();
1218                 outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1219             }
1220             if (scanner.token == Token.CPINDEX) {
1221                 outerClass = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1222             }
1223 
1224             if (scanner.token == SEMICOLON) {
1225                 pic_tracecreate(mod, nameCell, innerClass, outerClass);
1226                 cd.addInnerClass(mod, nameCell, innerClass, outerClass);
1227             } else {
1228                 pic_error();
1229             }
1230         } else {
1231             pic_error();
1232         }
1233     }
1234 
1235     private void pic_tracecreate(int mod, ConstCell nameCell, ConstCell innerClass, ConstCell outerClass) {
1236         // throw error, IC is not recognizable
1237         env.trace(" Creating InnerClass: [" + Modifiers.toString(mod, CF_Context.CTX_INNERCLASS) + "], ");
1238 
1239         if (nameCell != pool.getCell(0)) {
1240             ConstValue value = nameCell.ref;
1241             if (value != null) {
1242                 env.trace(value.toString() + " = ");
1243             }
1244         }
1245 
1246         ConstValue_Cell ici_val = (ConstValue_Cell) innerClass.ref;
1247         ConstCell ici_ascii = ici_val.cell;
1248         // Constant pool may not be numberized yet.
1249         //
1250         // check values before dereference on a trace.
1251         if (ici_ascii.ref == null) {
1252             env.trace("<#cpx-unresolved> ");
1253         } else {
1254             ConstValue_String cval = (ConstValue_String) ici_ascii.ref;
1255             if (cval.value == null) {
1256                 env.trace("<#cpx-0> ");
1257             } else {
1258                 env.trace(cval.value + " ");
1259             }
1260         }
1261 
1262         if (outerClass != pool.getCell(0)) {
1263             if (outerClass.arg != 0) {
1264                 ConstValue_Cell oci_val = (ConstValue_Cell) outerClass.ref;
1265                 ConstCell oci_ascii = oci_val.cell;
1266                 if (oci_ascii.ref == null) {
1267                     env.trace(" of <#cpx-unresolved>  ");
1268                 } else {
1269                     ConstValue_String cval = (ConstValue_String) oci_ascii.ref;
1270                     if (cval.value == null) {
1271                         env.trace(" of <#cpx-0>  ");
1272                     } else {
1273                         env.trace(" of " + cval.value);
1274                     }
1275                 }
1276             }
1277         }
1278 
1279         env.traceln("");
1280     }
1281 
1282     private void pic_error() {
1283         // throw error, IC is not recognizable
1284         env.error(scanner.pos, "invalid.innerclass");
1285         throw new Scanner.SyntaxError();
1286     }
1287 
1288     /**
1289      * The match() method is used to quickly match opening
1290      * brackets (ie: '(', '{', or '[') with their closing
1291      * counter part. This is useful during error recovery.<p>
1292      * <p>
1293      * Scan to a matching '}', ']' or ')'. The current scanner.token must be
1294      * a '{', '[' or '(';
1295      */
1296     private void match(Token open, Token close) throws IOException {
1297         int depth = 1;
1298 
1299         while (true) {
1300             scanner.scan();
1301             if (scanner.token == open) {
1302                 depth++;
1303             } else if (scanner.token == close) {
1304                 if (--depth == 0) {
1305                     return;
1306                 }
1307             } else if (scanner.token == Token.EOF) {
1308                 env.error(scanner.pos, "unbalanced.paren");
1309                 return;
1310             }
1311         }
1312     }
1313 
1314     /**
1315      * Recover after a syntax error in a field. This involves
1316      * discarding scanner.tokens until an EOF or a possible legal
1317      * continuation is encountered.
1318      */
1319     private void recoverField() throws Scanner.SyntaxError, IOException {
1320         while (true) {
1321             switch (scanner.token) {
1322                 case EOF:
1323                 case STATIC:
1324                 case FINAL:
1325                 case PUBLIC:
1326                 case PRIVATE:
1327                 case SYNCHRONIZED:
1328                 case TRANSIENT:
1329                 case PROTECTED:
1330                 case VOLATILE:
1331                 case NATIVE:
1332 //                case INTERFACE: see below
1333                 case ABSTRACT:
1334                 case ANNOTATION_ACCESS:
1335                     // possible begin of a field, continue
1336                     return;
1337 
1338                 case LBRACE:
1339                     match(Token.LBRACE, Token.RBRACE);
1340                     scanner.scan();
1341                     break;
1342 
1343                 case LPAREN:
1344                     match(Token.LPAREN, Token.RPAREN);
1345                     scanner.scan();
1346                     break;
1347 
1348                 case LSQBRACKET:
1349                     match(Token.LSQBRACKET, Token.RSQBRACKET);
1350                     scanner.scan();
1351                     break;
1352 
1353                 case RBRACE:
1354                 case INTERFACE:
1355                 case CLASS:
1356                 case IMPORT:
1357                 case PACKAGE:
1358                     // begin of something outside a class, panic more
1359                     endClass();
1360                     scanner.debugStr("    [Parser.recoverField]: pos: [" + scanner.pos + "]: ");
1361                     throw new Scanner.SyntaxError().Fatal();
1362                 default:
1363                     // don't know what to do, skip
1364                     scanner.scan();
1365                     break;
1366             }
1367         }
1368     }
1369 
1370     /**
1371      * Parse a class or interface declaration.
1372      */
1373     private void parseClass(int mod) throws IOException {
1374         int posa = scanner.pos;
1375         debugStr("   [Parser.parseClass]:  Begin ");
1376         // check access modifiers:
1377         Modifiers.checkClassModifiers(env, mod, scanner);
1378 
1379         if (cd == null) {
1380             cd = new ClassData(env, currentCFV.clone());
1381             pool = cd.pool;
1382         }
1383 
1384         if (clsAnnttns != null) {
1385             cd.addAnnotations(clsAnnttns);
1386         }
1387 
1388         // move the tokenizer to the identifier:
1389         if (scanner.token == Token.CLASS) {
1390             scanner.scan();
1391         } else if (scanner.token == Token.ANNOTATION) {
1392             scanner.scan();
1393             if (scanner.token == Token.INTERFACE) {
1394                 mod |= ACC_ANNOTATION | ACC_INTERFACE;
1395                 scanner.scan();
1396             } else {
1397                 env.error(scanner.prevPos, "token.expected", Token.ANNOTATION.parseKey() + Token.INTERFACE.parseKey());
1398                 throw new Scanner.SyntaxError();
1399             }
1400         }
1401 
1402         // Parse the class name
1403         ConstCell nm = cpParser.parseConstRef(ConstType.CONSTANT_CLASS, null, true);
1404 
1405         if (scanner.token == Token.FIELD) { // DOT
1406             String fileExtension;
1407             scanner.scan();
1408             switch (scanner.token) {
1409                 case STRINGVAL:
1410                     fileExtension = scanner.stringValue;
1411                     break;
1412                 case IDENT:
1413                     fileExtension = scanner.idValue;
1414                     break;
1415                 default:
1416                     env.error(scanner.pos, "name.expected");
1417                     throw new Scanner.SyntaxError();
1418             }
1419             scanner.scan();
1420             cd.fileExtension = "." + fileExtension;
1421         } else if (scanner.token == Token.MODULE) {
1422             env.error(scanner.prevPos, "token.expected", Token.OPEN.parseKey());
1423             throw new Scanner.SyntaxError();
1424         } else if (scanner.token == SEMICOLON) {
1425             // drop the semi-colon following a name
1426             scanner.scan();
1427         }
1428 
1429         // Parse extends clause
1430         ConstCell sup = null;
1431         if (scanner.token == Token.EXTENDS) {
1432             scanner.scan();
1433             sup = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1434             while (scanner.token == COMMA) {
1435                 scanner.scan();
1436                 env.error(posa, "multiple.inherit");
1437                 cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1438             }
1439         }
1440 
1441         // Parse implements clause
1442         ArrayList<Argument> impl = new ArrayList<>();
1443         if (scanner.token == Token.IMPLEMENTS) {
1444             do {
1445                 scanner.scan();
1446                 Argument intf = cpParser.parseConstRef(ConstType.CONSTANT_CLASS);
1447                 if (impl.contains(intf)) {
1448                     env.error(posa, "warn.intf.repeated", intf);
1449                 } else {
1450                     impl.add(intf);
1451                 }
1452             } while (scanner.token == COMMA);
1453         }
1454         parseVersion();
1455         scanner.expect(Token.LBRACE);
1456 
1457         // Begin a new class
1458         cd.init(mod, nm, sup, impl);
1459 
1460         // Parse constant declarations
1461 
1462         // Parse class members
1463         while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) {
1464             switch (scanner.token) {
1465                 case SEMICOLON:
1466                     // Empty fields are allowed
1467                     scanner.scan();
1468                     break;
1469                 case CONST:
1470                     scanner.scan();
1471                     parseConstDef();
1472                     explicitcp = true;
1473                     break;
1474                 default:   // scanner.token is some member.
1475                     parseClassMembers();
1476             }  // end switch
1477         } // while
1478         scanner.expect(Token.RBRACE);
1479         // End the class
1480         endClass();
1481     } // end parseClass
1482 
1483     /**
1484      * Parses a package or type name in a module statement(s)
1485      */
1486     private String parseTypeName() throws IOException {
1487         String name = "", field = "";
1488         while (true) {
1489             if (scanner.token.possibleModuleName()) {
1490                 name = name + field + scanner.idValue;
1491                 scanner.scan();
1492             } else {
1493                 env.error(scanner.pos, "name.expected", "\"" + scanner.token.parseKey() + "\"");
1494                 throw new Scanner.SyntaxError();
1495             }
1496             if (scanner.token == Token.FIELD) {
1497                 env.error(scanner.pos, "warn.dot.will.be.converted");
1498                 field = "/";
1499                 scanner.scan();
1500             } else {
1501                 break;
1502             }
1503         }
1504         return name;
1505     }
1506 
1507     /**
1508      * Parses a module name in a module statement(s)
1509      */
1510     private String parseModuleName() throws IOException {
1511         String name = "", field = "";
1512         while (true) {
1513             if (scanner.token.possibleModuleName()) {
1514                 name = name + field + scanner.idValue;
1515                 scanner.scanModuleStatement();
1516             } else {
1517                 env.error(scanner.pos, "module.name.expected", "\"" + scanner.token.parseKey() + "\"");
1518                 throw new Scanner.SyntaxError().Fatal();
1519             }
1520             if (scanner.token == Token.FIELD) {
1521                 field = Character.toString((char) scanner.token.value());
1522                 scanner.scanModuleStatement();
1523             } else {
1524                 break;
1525             }
1526         }
1527         return name;
1528     }
1529 
1530     /**
1531      * Parse a module declaration.
1532      */
1533     private void parseModule() throws IOException {
1534         debugStr("   [Parser.parseModule]:  Begin ");
1535         if (cd == null) {
1536             cd = new ClassData(env, currentCFV.clone());
1537             pool = cd.pool;
1538         }
1539         if (clsAnnttns != null) {
1540             cd.addAnnotations(clsAnnttns);
1541         }
1542         moduleAttribute = new ModuleAttr(cd);
1543 
1544         if (scanner.token == Token.OPEN) {
1545             moduleAttribute.openModule();
1546             scanner.scan();
1547         }
1548 
1549         // move the tokenizer to the identifier:
1550         if (scanner.token == Token.MODULE) {
1551             scanner.scanModuleStatement();
1552             // scanner.scan();
1553         } else {
1554             env.error(scanner.pos, "token.expected", Token.MODULE.parseKey());
1555             throw new Scanner.SyntaxError().Fatal();
1556         }
1557         // Parse the module name
1558         String moduleName = parseModuleName();
1559         if (moduleName.isEmpty()) {
1560             env.error(scanner.pos, "name.expected");
1561             throw new Scanner.SyntaxError().Fatal();
1562         }
1563         moduleAttribute.setModuleName(moduleName);
1564 
1565         parseVersion();
1566         scanner.expect(Token.LBRACE);
1567 
1568         // Begin a new class as module
1569         cd.initAsModule();
1570 
1571         // Parse module statement(s)
1572         while ((scanner.token != Token.EOF) && (scanner.token != Token.RBRACE)) {
1573             switch (scanner.token) {
1574                 case REQUIRES:
1575                     scanRequires(moduleAttribute.requires);
1576                     break;
1577                 case EXPORTS:
1578                     scanStatement(moduleAttribute.exports,
1579                             this::parseTypeName,
1580                             this::parseModuleName,
1581                             Token.TO,
1582                             true,
1583                             "exports.expected");
1584                     break;
1585                 case OPENS:
1586                     scanStatement(moduleAttribute.opens,
1587                             this::parseTypeName,
1588                             this::parseModuleName,
1589                             Token.TO, true, "opens.expected");
1590                     break;
1591                 case USES:
1592                     scanStatement(moduleAttribute.uses, "uses.expected");
1593                     break;
1594                 case PROVIDES:
1595                     scanStatement(moduleAttribute.provides,
1596                             this::parseTypeName,
1597                             this::parseTypeName,
1598                             Token.WITH,
1599                             false,
1600                             "provides.expected");
1601                     break;
1602                 case SEMICOLON:
1603                     // Empty fields are allowed
1604                     scanner.scan();
1605                     break;
1606                 default:
1607                     env.error(scanner.pos, "module.statement.expected");
1608                     throw new Scanner.SyntaxError().Fatal();
1609             }  // end switch
1610         } // while
1611         scanner.expect(Token.RBRACE);
1612         // End the module
1613         endModule();
1614     } // end parseModule
1615 
1616     /**
1617      * Scans  ModuleStatement: requires [transitive] [static] ModuleName ;
1618      */
1619     private void scanRequires(BiConsumer<String, Integer> action) throws IOException {
1620         int flags = 0;
1621         String mn = "";
1622         scanner.scanModuleStatement();
1623         while (scanner.token != SEMICOLON) {
1624             switch (scanner.token) {
1625                 case STATIC:
1626                     if (((flags & (1 << Module.Modifier.ACC_STATIC_PHASE.asInt())) != 0) || !mn.isEmpty()) {
1627                         env.error(scanner.pos, "requires.expected");
1628                         throw new Scanner.SyntaxError().Fatal();
1629                     }
1630                     flags |= Module.Modifier.ACC_STATIC_PHASE.asInt();
1631                     break;
1632                 case TRANSITIVE:
1633                     if (((flags & (1 << Module.Modifier.ACC_TRANSITIVE.asInt())) != 0) || !mn.isEmpty()) {
1634                         env.error(scanner.pos, "requires.expected");
1635                         throw new Scanner.SyntaxError().Fatal();
1636                     }
1637                     flags |= Module.Modifier.ACC_TRANSITIVE.asInt();
1638                     break;
1639                 case IDENT:
1640                     if (!mn.isEmpty()) {
1641                         env.error(scanner.pos, "requires.expected");
1642                         throw new Scanner.SyntaxError().Fatal();
1643                     }
1644                     mn = parseModuleName();
1645                     continue;
1646                 default:
1647                     if (mn.isEmpty() && scanner.token.possibleModuleName()) {
1648                         mn = parseModuleName();
1649                         continue;
1650                     } else {
1651                         env.error(scanner.pos, "requires.expected");
1652                         throw new Scanner.SyntaxError().Fatal();
1653                     }
1654             }
1655             scanner.scanModuleStatement();
1656         }
1657         // Token.SEMICOLON
1658         if (mn.isEmpty()) {
1659             env.error(scanner.pos, "requires.expected");
1660             throw new Scanner.SyntaxError().Fatal();
1661         }
1662         action.accept(mn, flags);
1663         scanner.scanModuleStatement();
1664     }
1665 
1666     /**
1667      * Scans  ModuleStatement: uses TypeName;
1668      */
1669     private void scanStatement(Consumer<Set<String>> action, String err) throws IOException {
1670         HashSet<String> names = scanList(() -> scanner.scan(), this::parseTypeName, err, true);
1671         // Token.SEMICOLON
1672         if (names.size() != 1) {
1673             env.error(scanner.pos, err);
1674             throw new Scanner.SyntaxError().Fatal();
1675         }
1676         action.accept(names);
1677         scanner.scan();
1678     }
1679 
1680     /**
1681      * Scans  Module Statement(s):
1682      * exports  packageName [to ModuleName {, ModuleName}] ;
1683      * opens    packageName [to ModuleName {, ModuleName}] ;
1684      * provides TypeName with TypeName [,typeName] ;
1685      */
1686     private void scanStatement(BiConsumer<String, Set<String>> action,
1687                                NameSupplier source,
1688                                NameSupplier target,
1689                                Token startList,
1690                                boolean emptyListAllowed,
1691                                String err) throws IOException {
1692         String typeName = "";
1693         HashSet<String> names = new HashSet<>();
1694         scanner.scan();
1695         while (scanner.token != SEMICOLON) {
1696             if (scanner.token == Token.IDENT) {
1697                 if (typeName.isEmpty()) {
1698                     typeName = source.get();
1699                     continue;
1700                 }
1701                 env.error(scanner.pos, err);
1702                 throw new Scanner.SyntaxError().Fatal();
1703             }
1704             if (scanner.token == startList) {
1705                 if (typeName.isEmpty()) {
1706                     env.error(scanner.pos, err);
1707                     throw new Scanner.SyntaxError().Fatal();
1708                 }
1709                 names = scanList(scanner.token == Token.TO ? () -> scanner.scanModuleStatement() : () -> scanner.scan(), target, err, false);
1710                 break;
1711             } else {
1712                 env.error(scanner.pos, err);
1713                 throw new Scanner.SyntaxError().Fatal();
1714             }
1715         }
1716         // Token.SEMICOLON
1717         if (typeName.isEmpty() || (names.isEmpty() && !emptyListAllowed)) {
1718             env.error(scanner.pos, err);
1719             throw new Scanner.SyntaxError().Fatal();
1720         }
1721         action.accept(typeName, names);
1722         scanner.scan();
1723     }
1724 
1725     /**
1726      * Scans the "to" or "with" part of ModuleStatement: exports PackageName  [to  ModuleName {, ModuleName}] ;,
1727      * opens  packageName   [to  ModuleName {, ModuleName}] ;
1728      * provides TypeName with TypeName [,typeName] ;
1729      * uses TypeName;
1730      * : [ModuleName {, ModuleName}]; , [TypeName [,typeName]]; or TypeName;
1731      */
1732     private HashSet<String> scanList(Method scanMethod, NameSupplier target, String err, boolean onlyOneElement) throws IOException {
1733         HashSet<String> names = new HashSet<>();
1734         boolean comma = false, first = true;
1735         scanMethod.call();
1736         while (scanner.token != SEMICOLON) {
1737             switch (scanner.token) {
1738                 case COMMA:
1739                     if (comma || first || onlyOneElement) {
1740                         env.error(scanner.pos, err);
1741                         throw new Scanner.SyntaxError().Fatal();
1742                     }
1743                     comma = true;
1744                     break;
1745                 case IDENT:
1746                     if (!first && !comma) {
1747                         env.error(scanner.pos, err);
1748                         throw new Scanner.SyntaxError().Fatal();
1749                     }
1750                     names.add(target.get());
1751                     comma = false;
1752                     first = false;
1753                     continue;
1754                 default:
1755                     env.error(scanner.pos, err);
1756                     throw new Scanner.SyntaxError().Fatal();
1757             }
1758             scanner.scan();
1759         }
1760         // Token.SEMICOLON
1761         if (names.isEmpty() || comma) {
1762             env.error(scanner.pos, err);
1763             throw new Scanner.SyntaxError().Fatal();
1764         }
1765         return names;
1766     }
1767 
1768     private void parseClassMembers() throws IOException {
1769         debugScan("[Parser.parseClassMembers]:  Begin ");
1770         // Parse annotations
1771         if (scanner.token == Token.ANNOTATION) {
1772             memberAnnttns = annotParser.scanAnnotations();
1773         }
1774         // Parse modifiers
1775         int mod = scanModifiers();
1776         try {
1777             switch (scanner.token) {
1778                 case FIELDREF:
1779                     scanner.scan();
1780                     parseField(mod);
1781                     break;
1782                 case METHODREF:
1783                     scanner.scan();
1784                     parseMethod(mod);
1785                     break;
1786                 case INNERCLASS:
1787                     scanner.scan();
1788                     parseInnerClass(mod);
1789                     break;
1790                 case BOOTSTRAPMETHOD:
1791                     scanner.scan();
1792                     parseCPXBootstrapMethod();
1793                     break;
1794                 case NESTHOST:
1795                     if (cd.nestHostAttributeExists()) {
1796                         env.error(scanner.pos, "extra.nesthost.attribute");
1797                         throw new Scanner.SyntaxError();
1798                     } else if (cd.nestMembersAttributesExist()) {
1799                         env.error(scanner.pos, "both.nesthost.nestmembers.found");
1800                         throw new Scanner.SyntaxError();
1801                     }
1802                     scanner.scan();
1803                     parseNestHost();
1804                     break;
1805                 case NESTMEMBERS:
1806                     if (cd.nestMembersAttributesExist()) {
1807                         env.error(scanner.pos, "extra.nestmembers.attribute");
1808                         throw new Scanner.SyntaxError();
1809                     } else if (cd.nestHostAttributeExists()) {
1810                         env.error(scanner.pos, "both.nesthost.nestmembers.found");
1811                         throw new Scanner.SyntaxError();
1812                     }
1813                     scanner.scan();
1814                     parseClasses(list -> cd.addNestMembers(list));
1815                     break;
1816                 case PERMITTEDSUBCLASSES:         // JEP 360
1817                     if (cd.nestMembersAttributesExist()) {
1818                         env.error(scanner.pos, "extra.permittedsubclasses.attribute");
1819                         throw new Scanner.SyntaxError();
1820                     }
1821                     scanner.scan();
1822                     parseClasses(list -> cd.addPermittedSubclasses(list));
1823                     break;
1824                 case RECORD:                    // JEP 359
1825                     if (cd.recordAttributeExists()) {
1826                         env.error(scanner.pos, "extra.record.attribute");
1827                         throw new Scanner.SyntaxError();
1828                     }
1829                     scanner.scan();
1830                     parseRecord();
1831                     break;
1832                 case PRELOAD:
1833                     if (cd.preloadAttributeExists()) {
1834                         env.error(scanner.pos, "extra.preload.attribute");
1835                         throw new Scanner.SyntaxError();
1836                     }
1837                     scanner.scan();
1838                     parseClasses(list -> cd.addPreloads(list));
1839                     break;
1840                 default:
1841                     env.error(scanner.pos, "field.expected");
1842                     throw new Scanner.SyntaxError();
1843             }  // end switch
1844         } catch (Scanner.SyntaxError e) {
1845             recoverField();
1846         }
1847         memberAnnttns = null;
1848     }
1849 
1850     /**
1851      * Recover after a syntax error in the file.
1852      * This involves discarding scanner.tokens until an EOF
1853      * or a possible legal continuation is encountered.
1854      */
1855     private void recoverFile() throws IOException {
1856         while (true) {
1857             env.traceln("recoverFile: scanner.token=" + scanner.token);
1858             switch (scanner.token) {
1859                 case CLASS:
1860                 case INTERFACE:
1861                     // Start of a new source file statement, continue
1862                     return;
1863 
1864                 case LBRACE:
1865                     match(Token.LBRACE, Token.RBRACE);
1866                     scanner.scan();
1867                     break;
1868 
1869                 case LPAREN:
1870                     match(Token.LPAREN, Token.RPAREN);
1871                     scanner.scan();
1872                     break;
1873 
1874                 case LSQBRACKET:
1875                     match(Token.LSQBRACKET, Token.RSQBRACKET);
1876                     scanner.scan();
1877                     break;
1878 
1879                 case EOF:
1880                     return;
1881 
1882                 default:
1883                     // Don't know what to do, skip
1884                     scanner.scan();
1885                     break;
1886             }
1887         }
1888     }
1889 
1890     /**
1891      * End class
1892      */
1893     private void endClass() {
1894         if (explicitcp) {
1895             // Fix references in the constant pool (for explicitly coded CPs)
1896             pool.fixRefsInPool();
1897             // Fix any bootstrap Method references too
1898             cd.relinkBootstrapMethods();
1899         }
1900         cd.endClass();
1901         clsDataList.add(cd);
1902         cd = null;
1903     }
1904 
1905     /**
1906      * End module
1907      */
1908     private void endModule() {
1909         cd.endModule(moduleAttribute);
1910         clsDataList.add(cd);
1911         cd = null;
1912     }
1913 
1914     final ClassData[] getClassesData() {
1915         return clsDataList.toArray(new ClassData[0]);
1916     }
1917 
1918     /**
1919      * Determines whether the JASM file is for a package-info class
1920      * or for a module-info class.
1921      * <p>
1922      * creates the correct kind of ClassData accordingly.
1923      *
1924      * @throws IOException
1925      */
1926     private void parseJasmPackages() throws IOException {
1927         try {
1928             // starting annotations could either be
1929             // a package annotation, or a class annotation
1930             if (scanner.token == Token.ANNOTATION) {
1931                 if (cd == null) {
1932                     cd = new ClassData(env, currentCFV.clone());
1933                     pool = cd.pool;
1934                 }
1935                 pkgAnnttns = annotParser.scanAnnotations();
1936             }
1937             if (scanner.token == Token.PACKAGE) {
1938                 // Package statement
1939                 scanner.scan();
1940                 int where = scanner.pos;
1941                 String id = parseIdent();
1942                 parseVersionPkg();
1943                 scanner.expect(SEMICOLON);
1944 
1945                 if (pkg == null) {
1946                     pkg = id;
1947                     pkgPrefix = id + "/";
1948                 } else {
1949                     env.error(where, "package.repeated");
1950                 }
1951                 debugScan("[Parser.parseJasmPackages] {PARSED} package-prefix: " + pkgPrefix + " ");
1952             }
1953         } catch (Scanner.SyntaxError e) {
1954             recoverFile();
1955         }
1956         // skip bogus semi colons
1957         while (scanner.token == SEMICOLON) {
1958             scanner.scan();
1959         }
1960 
1961         // checks that we compile module or package compilation unit
1962         if (scanner.token == Token.EOF) {
1963             env.traceln("Scanner:  EOF");
1964             String sourceName = env.getSimpleInputFileName();
1965             int mod = ACC_INTERFACE | ACC_ABSTRACT;
1966 
1967             // package-info
1968             if (sourceName.endsWith("package-info.jasm")) {
1969                 env.traceln("Creating \"package-info.jasm\": package: " + pkg + " " + currentCFV.asString());
1970 
1971                 if (cd == null) {
1972                     cd = new ClassData(env, currentCFV.clone());
1973                     pool = cd.pool;
1974                 } else {
1975                     cd.cfv = currentCFV.clone();
1976                 }
1977                 ConstCell me = pool.FindCellClassByName(pkgPrefix + "package-info");
1978 
1979                 // Interface package-info should be marked synthetic and abstract
1980                 if (currentCFV.major_version() > 49) {
1981                     mod |= SYNTHETIC_ATTRIBUTE;
1982                 }
1983                 cd.init(mod, me, new ConstCell(0), null);
1984 
1985                 if (pkgAnnttns != null) {
1986                     cd.addAnnotations(pkgAnnttns);
1987                 }
1988 
1989                 endClass();
1990             }
1991             return;
1992         }
1993 
1994         if (pkg == null && pkgAnnttns != null) { // RemoveModules
1995             clsAnnttns = pkgAnnttns;
1996             pkgAnnttns = null;
1997         }
1998     }
1999 
2000     /**
2001      * Parse an Jasm file.
2002      */
2003     void parseFile() {
2004         try {
2005             // First, parse any package identifiers (and associated package annotations)
2006             parseJasmPackages();
2007 
2008             while (scanner.token != Token.EOF) {
2009                 // Second, parse any class identifiers (and associated class annotations)
2010                 try {
2011                     // Parse annotations
2012                     if (scanner.token == Token.ANNOTATION) {
2013                         if (cd == null) {
2014                             cd = new ClassData(env, currentCFV.clone());
2015                             pool = cd.pool;
2016                         } else {
2017                             cd.cfv = currentCFV.clone();
2018                         }
2019                         clsAnnttns = annotParser.scanAnnotations();
2020                     }
2021 
2022                     // Parse class modifiers
2023                     int mod = scanModifiers();
2024                     if (mod == 0) {
2025                         switch (scanner.token) {
2026                             case OPEN:
2027                             case MODULE:
2028                             case CLASS:
2029                             case CPINDEX:
2030                             case STRINGVAL:
2031                             case IDENT:
2032                                 // this is a class declaration anyway
2033                                 break;
2034                             case SEMICOLON:
2035                                 // Bogus semi colon
2036                                 scanner.scan();
2037                                 continue;
2038                             default:
2039                                 // no class declaration found
2040                                 debugScan(" [Parser.parseFile]: ");
2041                                 env.error(scanner.pos, "toplevel.expected");
2042                                 throw new Scanner.SyntaxError();
2043                         }
2044                     } else if (Modifiers.isInterface(mod) && (scanner.token != Token.CLASS)) {
2045                         // rare syntactic sugar:
2046                         // interface <ident> == abstract interface class <ident>
2047                         mod |= ACC_ABSTRACT;
2048                     }
2049                     if (scanner.token == Token.MODULE || scanner.token == Token.OPEN)
2050                         parseModule();
2051                     else
2052                         parseClass(mod);
2053                     clsAnnttns = null;
2054 
2055                 } catch (Scanner.SyntaxError e) {
2056                     // KTL
2057                     env.traceln("^^^^^^^ Syntax Error ^^^^^^^^^^^^");
2058                     if (scanner.debugFlag)
2059                         e.printStackTrace();
2060                     if (e.isFatal()) {
2061                         break;
2062                     }
2063                     recoverFile();
2064                 }
2065             }
2066         } catch (IOException e) {
2067             env.error(scanner.pos, "io.exception", env.getSimpleInputFileName());
2068         } catch (Error er) {
2069             er.printStackTrace();
2070         }
2071     } //end parseFile
2072 
2073     @FunctionalInterface
2074     interface NameSupplier {
2075         String get() throws IOException;
2076     }
2077 
2078     @FunctionalInterface
2079     interface Method {
2080         void call() throws IOException;
2081     }
2082 
2083     /**
2084      * The main compile error for the parser
2085      */
2086     static class CompilerError extends Error {
2087 
2088         CompilerError(String message) {
2089             super(message);
2090         }
2091     }
2092 }  //end Parser