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 java.io.IOException;
 26 import java.util.ArrayList;
 27 import java.util.function.BiFunction;
 28 
 29 import static org.openjdk.asmtools.jasm.JasmTokens.Token;
 30 import static org.openjdk.asmtools.jasm.Tables.*;
 31 
 32 /**
 33  * ParserCP
 34  *
 35  * ParseCP is a parser class owned by Parser.java. It is primarily responsible for parsing
 36  * the constant pool and constant declarations.
 37  */
 38 public class ParserCP extends ParseBase {
 39 
 40     /**
 41      * Stop parsing a source file immediately and interpret any issue as an error
 42      */
 43     private boolean exitImmediately = false;
 44 
 45     /**
 46      * local handles on the scanner, main parser, and the error reporting env
 47      */
 48     /**
 49      * Visitor object
 50      */
 51     private ParserCPVisitor pConstVstr;
 52     /**
 53      * counter of left braces
 54      */
 55     private int lbrace = 0;
 56 
 57 
 58     /**
 59      * main constructor
 60      *
 61      * @param scanner
 62      * @param parser
 63      * @param env
 64      */
 65     protected ParserCP(Scanner scanner, Parser parser, Environment env) {
 66         super.init(scanner, parser, env);
 67         pConstVstr = new ParserCPVisitor();
 68     }
 69 
 70     /**
 71      * In particular cases it's necessary to interpret a warning issue as an error and
 72      * stop parsing a source file immediately
 73      * cpParser.setExitImmediately(true);
 74      * çparseConstRef(...);
 75      * cpParser.setExitImmediately(false);
 76      */
 77     public void setExitImmediately(boolean exitImmediately) {
 78         this.exitImmediately = exitImmediately;
 79     }
 80 
 81     public boolean isExitImmediately() {
 82         return exitImmediately;
 83     }
 84 
 85     /**
 86      * ParserCPVisitor
 87      *
 88      * This inner class overrides a constant pool visitor to provide specific parsing
 89      * instructions (per method) for each type of Constant.
 90      *
 91      * Note: since the generic visitor throws no exceptions, this derived class tunnels
 92      * the exceptions, rethrown in the visitEcept method.
 93      */
 94     class ParserCPVisitor extends ConstantPool.CPTagVisitor<ConstantPool.ConstValue> {
 95 
 96         private IOException IOProb;
 97         private Scanner.SyntaxError SyProb;
 98 
 99 
100         public ParserCPVisitor() {
101             IOProb = null;
102             SyProb = null;
103         }
104 
105         //This is the entry point for a visitor that tunnels exceptions
106         public ConstantPool.ConstValue visitExcept(ConstType tag) throws IOException, Scanner.SyntaxError {
107             IOProb = null;
108             SyProb = null;
109             debugStr("------- [ParserCPVisitor.visitExcept]: ");
110             ConstantPool.ConstValue ret = visit(tag);
111 
112             if (IOProb != null) {
113                 throw IOProb;
114             }
115 
116             if (SyProb != null) {
117                 throw SyProb;
118             }
119 
120             return ret;
121         }
122 
123         @Override
124         public ConstantPool.ConstValue visitUTF8(ConstType tag) {
125             debugStr("------- [ParserCPVisitor.visitUTF8]: ");
126             try {
127                 scanner.expect(Token.STRINGVAL);
128             } catch (IOException e) {
129                 IOProb = e;
130             }
131             ConstantPool.ConstValue_String obj
132                     = new ConstantPool.ConstValue_String(scanner.stringValue);
133             return obj;
134         }
135 
136         @Override
137         public ConstantPool.ConstValue visitInteger(ConstType tag) {
138             debugStr("------- [ParserCPVisitor.visitInteger]: ");
139             ConstantPool.ConstValue_Integer obj;
140             int v = 0;
141             try {
142                 if (scanner.token == Token.BITS) {
143                     scanner.scan();
144                     scanner.inBits = true;
145                 }
146                 v = scanner.intValue * scanner.sign;
147                 scanner.expect(Token.INTVAL);
148             } catch (IOException e) {
149                 IOProb = e;
150             }
151             obj = new ConstantPool.ConstValue_Integer(tag, v);
152             return obj;
153         }
154 
155         @Override
156         public ConstantPool.ConstValue visitLong(ConstType tag) {
157             debugStr("------- [ParserCPVisitor.visitLong]: ");
158             ConstantPool.ConstValue_Long obj = null;
159             try {
160                 long v;
161                 if (scanner.token == Token.BITS) {
162                     scanner.scan();
163                     scanner.inBits = true;
164                 }
165                 switch (scanner.token) {
166                     case INTVAL:
167                         v = scanner.intValue;
168                         break;
169                     case LONGVAL:
170                         v = scanner.longValue;
171                         break;
172                     default:
173                         env.error(scanner.prevPos, "token.expected", "Integer");
174                         throw new Scanner.SyntaxError();
175                 }
176                 obj = new ConstantPool.ConstValue_Long(tag, v * scanner.sign);
177                 scanner.scan();
178             } catch (IOException e) {
179                 IOProb = e;
180             } catch (Scanner.SyntaxError e) {
181                 SyProb = e;
182             }
183             return obj;
184         }
185 
186         @Override
187         public ConstantPool.ConstValue visitFloat(ConstType tag) {
188             debugStr("------- [ParserCPVisitor.visitFloat]: ");
189             ConstantPool.ConstValue_Integer obj = null;
190             try {
191                 int v;
192                 float f;
193                 scanner.inBits = false;  // this needs to be initialized for each float!
194                 if (scanner.token == Token.BITS) {
195                     scanner.scan();
196                     scanner.inBits = true;
197                 }
198 i2f:            {
199                     switch (scanner.token) {
200                         case INTVAL:
201                             if (scanner.inBits) {
202                                 v = scanner.intValue;
203                                 break i2f;
204                             } else {
205                                 f = (float) scanner.intValue;
206                                 break;
207                             }
208                         case FLOATVAL:
209                             f = scanner.floatValue;
210                             break;
211                         case DOUBLEVAL:
212                             f = (float) scanner.doubleValue; // to be excluded?
213                             break;
214                         case INF:
215                             f = Float.POSITIVE_INFINITY;
216                             break;
217                         case NAN:
218                             f = Float.NaN;
219                             break;
220                         default:
221                             env.traceln("token=" + scanner.token);
222                             env.error(scanner.pos, "token.expected", "<Float>");
223                             throw new Scanner.SyntaxError();
224                     }
225                     v = Float.floatToIntBits(f);
226                 }
227                 if (scanner.sign == -1) {
228                     v = v ^ 0x80000000;
229                 }
230                 obj = new ConstantPool.ConstValue_Integer(tag, v);
231                 scanner.scan();
232             } catch (IOException e) {
233                 IOProb = e;
234             } catch (Scanner.SyntaxError e) {
235                 SyProb = e;
236             }
237             return obj;
238         }
239 
240         @Override
241         public ConstantPool.ConstValue visitDouble(ConstType tag) {
242             debugStr("------- [ParserCPVisitor.visitDouble]: ");
243             ConstantPool.ConstValue_Long obj = null;
244             try {
245                 long v;
246                 double d;
247                 if (scanner.token == Token.BITS) {
248                     scanner.scan();
249                     scanner.inBits = true;
250                 }
251 d2l:            {
252                     switch (scanner.token) {
253                         case INTVAL:
254                             if (scanner.inBits) {
255                                 v = scanner.intValue;
256                                 break d2l;
257                             } else {
258                                 d = scanner.intValue;
259                                 break;
260                             }
261                         case LONGVAL:
262                             if (scanner.inBits) {
263                                 v = scanner.longValue;
264                                 break d2l;
265                             } else {
266                                 d = (double) scanner.longValue;
267                                 break;
268                             }
269                         case FLOATVAL:
270                             d = scanner.floatValue;
271                             break;
272                         case DOUBLEVAL:
273                             d = scanner.doubleValue;
274                             break;
275                         case INF:
276                             d = Double.POSITIVE_INFINITY;
277                             break;
278                         case NAN:
279                             d = Double.NaN;
280                             break;
281                         default:
282                             env.error(scanner.pos, "token.expected", "Double");
283                             throw new Scanner.SyntaxError();
284                     }
285                     v = Double.doubleToLongBits(d);
286                 }
287                 if (scanner.sign == -1) {
288                     v = v ^ 0x8000000000000000L;
289                 }
290                 obj = new ConstantPool.ConstValue_Long(tag, v);
291                 scanner.scan();
292             } catch (IOException e) {
293                 IOProb = e;
294             } catch (Scanner.SyntaxError e) {
295                 SyProb = e;
296             }
297             return obj;
298         }
299 
300         private ConstantPool.ConstCell visitName(ConstType tag) {
301             debugStr("------- [ParserCPVisitor.visitName]: ");
302             ConstantPool.ConstCell obj = null;
303             try {
304                 obj = parser.parseName();
305             } catch (IOException e) {
306                 IOProb = e;
307             }
308             return obj;
309         }
310 
311         @Override
312         public ConstantPool.ConstValue visitMethodtype(ConstType tag) {
313             debugStr("------- [ParserCPVisitor.visitMethodtype]: ");
314             ConstantPool.ConstValue_Cell obj = null;
315             ConstantPool.ConstCell cell = visitName(tag);
316             if (IOProb == null) {
317                 obj = new ConstantPool.ConstValue_Cell(tag, cell);
318             }
319             return obj;
320         }
321 
322         @Override
323         public ConstantPool.ConstValue visitString(ConstType tag) {
324             debugStr("------- [ParserCPVisitor.visitString]: ");
325             ConstantPool.ConstValue_Cell obj = null;
326             ConstantPool.ConstCell cell = visitName(tag);
327             if (IOProb == null) {
328                 obj = new ConstantPool.ConstValue_Cell(tag, cell);
329             }
330             return obj;
331         }
332 
333         @Override
334         public ConstantPool.ConstValue visitClass(ConstType tag) {
335             debugStr("------- [ParserCPVisitor.visitClass]: ");
336             ConstantPool.ConstValue_Cell obj = null;
337             try {
338                 ConstantPool.ConstCell cell = parser.parseClassName(true);
339                 obj = new ConstantPool.ConstValue_Cell(tag, cell);
340             } catch (IOException e) {
341                 IOProb = e;
342             }
343             return obj;
344         }
345 
346         @Override
347         public ConstantPool.ConstValue visitMethodhandle(ConstType tag) {
348             debugStr("------- [ParserCPVisitor.visitMethodHandle]: ");
349             ConstantPool.ConstValue_Pair obj = null;
350             try {
351                 ConstantPool.ConstCell refCell;
352                 ConstantPool.ConstCell subtagCell;
353                 SubTag subtag;
354                 // MethodHandle    [INVOKESUBTAG|INVOKESUBTAG_INDEX] :    CONSTANT_FIELD | [FIELDREF|METHODREF|INTERFACEMETHODREF]
355                 if (scanner.token == Token.INTVAL) {
356                     // INVOKESUBTAG_INDEX
357                     // Handle explicit constant pool form
358                     subtag = subtag(scanner.intValue);
359                     subtagCell = new ConstantPool.ConstCell(subtag.value());
360                     scanner.scan();
361                     scanner.expect(Token.COLON);
362                     if (scanner.token == Token.CPINDEX) {
363                         // CONSTANT_FIELD
364                         int cpx = scanner.intValue;
365                         refCell = parser.pool.getCell(cpx);
366                         scanner.scan();
367                     } else {
368                         // [FIELDREF|METHODREF|INTERFACEMETHODREF]
369                         refCell = parser.parseMethodHandle(subtag);
370                     }
371                 } else {
372                     // INVOKESUBTAG : REF_INVOKEINTERFACE, REF_NEWINVOKESPECIAL, ...
373                     // normal JASM
374                     subtag = parser.parseSubtag();
375                     subtagCell = new ConstantPool.ConstCell(subtag.value());
376                     scanner.expect(Token.COLON);
377                     if (scanner.token == Token.CPINDEX) {
378                         // CODETOOLS-7901522: Jasm doesn't allow to create REF_invoke* referring an InterfaceMethod
379                         // Parsing the case when refCell is CP index (#1)
380                         // const #1 = InterfaceMethod m:"()V";
381                         // const #2 = MethodHandle REF_invokeSpecial:#1;
382                         int cpx = scanner.intValue;
383                         refCell = parser.pool.getCell(cpx);
384                         scanner.scan();
385                     } else {
386                         refCell = parser.parseMethodHandle(subtag);
387                     }
388                 }
389                 obj = new ConstantPool.ConstValue_Pair(tag, subtagCell, refCell);
390             } catch (IOException e) {
391                 IOProb = e;
392             }
393             return obj;
394         }
395 
396         private ConstantPool.ConstValue_Pair visitMember(ConstType tag) {
397             debugStr("------- [ParserCPVisitor.visitMember]: ");
398             ConstantPool.ConstValue_Pair obj = null;
399             try {
400                 Token prevtoken = scanner.token;
401                 ConstantPool.ConstCell firstName, ClassCell, NameCell, NapeCell;
402                 firstName = parser.parseClassName(false);
403                 if (scanner.token == Token.FIELD) { // DOT
404                     scanner.scan();
405                     if (prevtoken == Token.CPINDEX) {
406                         ClassCell = firstName;
407                     } else {
408                         ClassCell = parser.pool.FindCell(ConstType.CONSTANT_CLASS, firstName);
409                     }
410                     NameCell = parser.parseName();
411                 } else {
412                     // no class provided - assume current class
413                     ClassCell = parser.cd.me;
414                     NameCell = firstName;
415                 }
416                 if (scanner.token == Token.COLON) {
417                     // name and type separately
418                     scanner.scan();
419                     NapeCell = parser.pool.FindCell(ConstType.CONSTANT_NAMEANDTYPE, NameCell, parser.parseName());
420                 } else {
421                     // name and type as single name
422                     NapeCell = NameCell;
423                 }
424                 obj = new ConstantPool.ConstValue_Pair(tag, ClassCell, NapeCell);
425             } catch (IOException e) {
426                 IOProb = e;
427             }
428             return obj;
429         }
430 
431         @Override
432         public ConstantPool.ConstValue visitField(ConstType tag) {
433             debugStr("------- [ParserCPVisitor.visitField]: ");
434             return visitMember(tag);
435         }
436 
437         @Override
438         public ConstantPool.ConstValue visitMethod(ConstType tag) {
439             debugStr("------- [ParserCPVisitor.visitMethod]: ");
440             return visitMember(tag);
441         }
442 
443         @Override
444         public ConstantPool.ConstValue visitInterfacemethod(ConstType tag) {
445             debugStr("------- [ParserCPVisitor.visitInterfacemethod]: ");
446             return visitMember(tag);
447         }
448 
449         @Override
450         public ConstantPool.ConstValue visitNameandtype(ConstType tag) {
451             debugStr("------- [ParserCPVisitor.visitNameandtype]: ");
452             ConstantPool.ConstValue_Pair obj = null;
453             try {
454                 ConstantPool.ConstCell NameCell = parser.parseName(), TypeCell;
455                 scanner.expect(Token.COLON);
456                 TypeCell = parser.parseName();
457                 obj = new ConstantPool.ConstValue_Pair(tag, NameCell, TypeCell);
458             } catch (IOException e) {
459                 IOProb = e;
460             }
461             return obj;
462         }
463 
464         @Override
465         public ConstantPool.ConstValue_IndyPair visitInvokedynamic(ConstType tag) {
466             debugStr("------- [ParserCPVisitor.visitInvokeDynamic]: ");
467             final BiFunction<BootstrapMethodData, ConstantPool.ConstCell, ConstantPool.ConstValue_IndyPair> ctor =
468                     (bsmData, napeCell) -> new ConstantPool.ConstValue_IndyPair(bsmData, napeCell);
469             return visitBsm(ctor);
470         }
471 
472         @Override
473         public ConstantPool.ConstValue_CondyPair visitDynamic(ConstType tag) {
474             debugStr("------- [ParserCPVisitor.visitDynamic]: ");
475             final BiFunction<BootstrapMethodData, ConstantPool.ConstCell, ConstantPool.ConstValue_CondyPair> ctor =
476                     (bsmData, napeCell) -> new ConstantPool.ConstValue_CondyPair(bsmData, napeCell);
477             return visitBsm(ctor);
478         }
479 
480         private <E extends ConstantPool.ConstValue_IndyOrCondyPair> E visitBsm(BiFunction<BootstrapMethodData, ConstantPool.ConstCell, E> ctor) {
481             E obj = null;
482             try {
483                 if (scanner.token == Token.INTVAL) {
484                     // Handle explicit constant pool form
485                     int bsmIndex = scanner.intValue;
486                     scanner.scan();
487                     scanner.expect(Token.COLON);
488                     if (scanner.token != Token.CPINDEX) {
489                         env.traceln("token=" + scanner.token);
490                         env.error(scanner.pos, "token.expected", "<CPINDEX>");
491                         throw new Scanner.SyntaxError();
492                     }
493                     int cpx = scanner.intValue;
494                     scanner.scan();
495                     // Put a placeholder in place of BSM.
496                     // resolve placeholder after the attributes are scanned.
497                     BootstrapMethodData bsmData = new BootstrapMethodData(bsmIndex);
498                     obj =   ctor.apply(bsmData, parser.pool.getCell(cpx));
499                 } else {
500                     // Handle full form
501                     ConstantPool.ConstCell MHCell = parser.pool.FindCell(parseConstValue(ConstType.CONSTANT_METHODHANDLE));
502                     scanner.expect(Token.COLON);
503                     ConstantPool.ConstCell NapeCell = parser.pool.FindCell(parseConstValue(ConstType.CONSTANT_NAMEANDTYPE));
504                     if(scanner.token == Token.LBRACE) {
505                         ParserCP.this.lbrace++;
506                         scanner.scan();
507                     }
508                     ArrayList<ConstantPool.ConstCell> bsm_args = new ArrayList<>(256);
509                     while(true) {
510                         if( ParserCP.this.lbrace > 0 ) {
511                             if(scanner.token == Token.RBRACE ) {
512                                 ParserCP.this.lbrace--;
513                                 scanner.scan();
514                                 break;
515                             } else if(scanner.token == Token.SEMICOLON) {
516                                 scanner.expect(Token.RBRACE);
517                             }
518                         } else if(scanner.token == Token.SEMICOLON) {
519                             break;
520                         }
521                         if (scanner.token == Token.COMMA) {
522                             scanner.scan();
523                         }
524                         bsm_args.add(parseConstRef(null));
525                     }
526                     if( ParserCP.this.lbrace == 0 ) {
527                         scanner.check(Token.SEMICOLON);
528                     }
529                     BootstrapMethodData bsmData = new BootstrapMethodData(MHCell, bsm_args);
530                     parser.cd.addBootstrapMethod(bsmData);
531                     obj = ctor.apply(bsmData, NapeCell);
532                 }
533             } catch (IOException e) {
534                 IOProb = e;
535             }
536             return obj;
537         }
538     } // End Visitor
539 
540     /**
541      * Parse CONSTVALUE
542      */
543     protected ConstantPool.ConstValue parseConstValue(ConstType tag) throws IOException, Scanner.SyntaxError {
544         return pConstVstr.visitExcept(tag);
545     }
546 
547     /**
548      * Parse [TAG] CONSTVALUE
549      */
550     protected ConstantPool.ConstValue parseTagConstValue(ConstType defaultTag) throws Scanner.SyntaxError, IOException {
551         return parseTagConstValue(defaultTag, null, false);
552     }
553 
554     private ConstType scanConstByID(boolean ignoreKeywords) {
555         ConstType tag = null;
556         if (!ignoreKeywords) {
557             ConstType tg = Tables.tag(scanner.idValue);
558             if (tg != null) {
559                 tag = tg;
560             }
561             debugStr(" *^*^*^*^ [ParserCP.scanConst]: {TAG = " + (tg == null ? "null" : tg.toString()) + " ");
562         }
563         return tag;
564     }
565 
566     private ConstType scanConstPrimVal() throws Scanner.SyntaxError, IOException {
567         ConstType tag = null;
568         switch (scanner.token) {
569             case INTVAL:
570                 tag = ConstType.CONSTANT_INTEGER;
571                 break;
572             case LONGVAL:
573                 tag = ConstType.CONSTANT_LONG;
574                 break;
575             case FLOATVAL:
576                 tag = ConstType.CONSTANT_FLOAT;
577                 break;
578             case DOUBLEVAL:
579                 tag = ConstType.CONSTANT_DOUBLE;
580                 break;
581             case STRINGVAL:
582             case BITS:
583             case IDENT:
584                 tag = ConstType.CONSTANT_STRING;
585                 break;
586             default:
587                 // problem - no constant value
588                 System.err.println("NEAR: " + scanner.token.printValue());
589                 env.error(scanner.pos, "value.expected");
590                 throw new Scanner.SyntaxError();
591         }
592         return tag;
593     }
594 
595     private void checkWrongTag(ConstType tag, ConstType defaultTag, ConstType default2Tag) throws Scanner.SyntaxError, IOException {
596         if (defaultTag != null) {
597             if (tag != defaultTag) {
598                 if (default2Tag == null) {
599                     if( exitImmediately ) {
600                         env.error("wrong.tag", defaultTag.parseKey());
601                         throw new Scanner.SyntaxError().Fatal();
602                     }
603                     env.error("warn.wrong.tag", defaultTag.parseKey());
604                 } else if (tag != default2Tag) {
605                     if( exitImmediately ) {
606                         env.error("wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey());
607                         throw new Scanner.SyntaxError().Fatal();
608                     }
609                     env.error("warn.wrong.tag2", defaultTag.parseKey(), default2Tag.parseKey());
610                 }
611             }
612         }
613     }
614 
615     protected ConstantPool.ConstValue parseTagConstValue(ConstType defaultTag, ConstType default2Tag, boolean ignoreKeywords) throws Scanner.SyntaxError, IOException {
616         debugScan(" *^*^*^*^ [ParserCP.parseTagConstValue]: Begin default_tag:  ignoreKeywords: " + (ignoreKeywords ? "true" : "false"));
617         // Lookup the Tag from the scanner
618         ConstType tag = scanConstByID(ignoreKeywords);
619         debugStr(" *^*^*^*^ [ParserCP.parseTagConstValue]: {tag = " + tag + ", defaulttag = " + defaultTag + "} ");
620 
621         // If the scanned tag is null
622         if (tag == null) {
623             // and, if the expected tag is null
624             if (defaultTag == null) {
625                 // return some other type of constant as the tag
626                 tag = scanConstPrimVal();
627             } else {
628                 // otherwise, make the scanned-tag the same constant-type
629                 // as the expected tag.
630                 tag = defaultTag;
631             }
632         } else {
633             // If the scanned tag is some constant type
634             // and the scanned type does not equal the expected type
635             checkWrongTag(tag, defaultTag, default2Tag);
636             scanner.scan();
637         }
638         return parseConstValue(tag);
639     } // end parseTagConstValue
640 
641     protected ConstantPool.ConstCell parseConstRef(ConstType defaultTag) throws Scanner.SyntaxError, IOException {
642         return parseConstRef(defaultTag, null, false);
643     }
644 
645     protected ConstantPool.ConstCell parseConstRef(ConstType defaultTag, ConstType default2Tag) throws Scanner.SyntaxError, IOException {
646         return parseConstRef(defaultTag, default2Tag, false);
647     }
648 
649     /**
650      * Parse an instruction argument, one of: * #NUMBER, #NAME, [TAG] CONSTVALUE
651      */
652     protected ConstantPool.ConstCell parseConstRef(ConstType defaultTag,
653             ConstType default2Tag,
654             boolean ignoreKeywords) throws Scanner.SyntaxError, IOException {
655         if (scanner.token == Token.CPINDEX) {
656             int cpx = scanner.intValue;
657             scanner.scan();
658             return parser.pool.getCell(cpx);
659         } else {
660             ConstantPool.ConstValue ref = parseTagConstValue(defaultTag, default2Tag, ignoreKeywords);
661             return parser.pool.FindCell(ref);
662         }
663     } // end parseConstRef
664 
665 }