1 30 31 package jbet; 32 import java.io.*; 33 import java.util.*; 34 35 54 55 56 public class Lexer { 57 58 abstract class SimpleStream { 59 abstract public int read() throws IOException ; 60 String filename; 61 int line; 62 SimpleStream(String filename, int line) { 63 this.filename = filename; 64 this.line = line; 65 } 66 } 67 68 private SimpleStream in; 69 70 71 public static final int ST_TAG = 1; public static final int ST_OPT = 2; public static final int ST_DASH = 3; 75 public static final int ST_NORMAL = 4; public static final int ST_TYPE = 5; 77 public static final int ST_STRING = 6; 78 public static final int ST_CONST = 7; 79 public static final int ST_ASM = 8; public static final int ST_ASM_ARG = 9; public static final int ST_COMMENT = 10; 82 83 static final int EOFCH = -1; 84 static final Token EOF = new Token(Token.EOF); 85 static final Token END_OF_OPTS = new Token(Token.END_OF_OPTS); 86 static final int SEMIHACKCH = 0x101; 87 88 int state; 91 92 StringFunction varFunction = null; 93 94 private String doSub(String s) { 95 return varFunction.f(s); 96 } 97 98 105 private int [] stateStack = new int [5]; 106 private int stateStacklen = 0; 107 108 public void push(int s) { 110 stateStack[stateStacklen++] = state; 111 state = s; 112 if (stateStacklen == stateStack.length) { 113 int [] ss = new int [ stateStacklen * 2 ]; 115 for (int i = 0; i < stateStacklen; i++) 116 ss[i] = stateStack[i]; 117 stateStack = ss; 118 } 119 } 120 public void pop() { 122 if (stateStacklen == 0) throw new RuntimeException 123 ("Lexer.pop called with empty stack"); 124 state = stateStack[ --stateStacklen ]; 125 } 126 127 128 129 private Stack streams = new Stack(); 130 131 132 private SimpleStream newStream(final Reader reader, final String fn, final int line) { 133 return new SimpleStream(fn, line) { 134 public int read() throws IOException { return reader.read(); }; 135 }; 136 } 137 private SimpleStream newStream(final InputStream inputStream, final String fn, final int line){ 138 return new SimpleStream(fn, line) { 139 public int read() throws IOException { return inputStream.read(); }; 140 }; 141 } 142 143 public Lexer (Reader reader, String fn) { 145 in = newStream(reader, fn, 1); 146 } 147 148 public Lexer (InputStream is, String fn) { 149 in = newStream(is, fn, 1); 150 } 151 152 153 154 156 private int saveCh = -2; 157 158 162 private int readch_lowlevel() throws ParseException { 163 int ch; 164 try { 165 if (saveCh == -2) 166 ch = in.read(); 167 else { 168 ch = saveCh; 169 saveCh = -2; 170 } 171 if (ch == '%') { 172 saveCh = in.read(); 173 if (saveCh == '(') { 174 saveCh = -2; 175 StringBuffer name = new StringBuffer (); 176 boolean include = false; 177 while (true) { 178 ch = in.read(); 179 if (ch==EOFCH) die ("unexpected end of file"); 180 if (ch==' ' && name.toString().equals("include")) { 181 name = new StringBuffer (); include = true; 184 continue; 185 } 186 if (ch==')') break; 187 name.append((char) ch); 188 } 189 SimpleStream newstr; 190 if (!include) { 191 String value = doSub(name.toString()); 192 if (value == null) throw new ParseException 193 ("unknown variable: " + name); 194 newstr = newStream(new StringReader(value), in.filename, -1); 195 } else 196 newstr = newStream(new FileInputStream(name.toString()), 197 name.toString(), 1); 198 streams.push(in); 199 in = newstr; 200 return readch_lowlevel(); 201 } 202 } 203 if (ch == '\n' && in.line != -1) 204 in.line++; 205 if (ch == '\n' && (state == ST_ASM || state == ST_ASM_ARG)) 206 ch = ';'; if (ch == EOFCH && streams.size() != 0) { 208 in = (SimpleStream) streams.pop(); 209 return readch_lowlevel(); 210 } 211 } catch (IOException e) { 212 throw new ParseException ("IOException caught while parseing"); 213 } 214 215 return ch; 216 } 217 218 219 222 private static final int maxlaCh = 2; 223 private int [] laChar = new int [ maxlaCh ]; private int numlaCh = 0; private int _justreadCh = -2; 228 231 private int laCh(int i) { 232 while (i > numlaCh) laChar[numlaCh++] = readch_lowlevel(); 234 return laChar[i-1]; 235 } 236 237 243 244 248 private int readch() { 249 if (numlaCh == 0) { 250 _justreadCh = readch_lowlevel(); 251 } else { 252 _justreadCh = laChar[0]; 253 for (int i = 0; i < numlaCh - 1; i++) 254 laChar[i] = laChar[i+1]; 255 numlaCh--; 256 } 257 return _justreadCh; 258 } 259 260 private int peekch() { 261 return laCh(1); 262 } 263 264 private char peekchar() { 265 return (char) peekch(); 266 } 267 268 private char readchar() { 269 return (char) readch(); 270 } 271 272 273 274 277 private static final int maxla = 2; 278 private Token [] laTok = new Token [maxla]; private int numla = 0; private Token _justread = null; 283 284 287 Token la(int i) { 289 while (i > numla) laTok[numla++] = read_token(); 291 return laTok[i - 1]; 292 } 293 294 300 301 public Token peek() { return la(1); }; 303 304 public void setstate (int s) { state = s; } 305 306 312 public Token read() { 313 if (numla == 0) { 314 _justread = read_token(); 315 } else { 316 _justread = laTok[0]; 317 for (int i = 0; i < numla - 1; i++) 318 laTok[i] = laTok[i+1]; 319 numla--; 320 } 321 322 return _justread; 323 } 324 325 public Token justread() { return _justread; }; 327 328 329 330 private void skip_ws() { 331 while (true) { 332 if (! Character.isWhitespace(peekchar())) return; 333 readch(); 334 } 335 } 336 337 private boolean border() { 338 return Character.isWhitespace(peekchar()) || peekch()==EOFCH; 339 } 340 341 public void die(String msg) { 343 SimpleStream str = null; 344 if (in.line == -1) 345 for (int i = streams.size(); --i >= 0;) { 346 str = (SimpleStream) streams.elementAt(i); 347 if (str.line != -1) break; 348 } 349 else 350 str = in; 351 352 if (str==null || str.filename == null || str.line == -1) 353 throw new ParseException(msg + " " + (str.filename==null)); 354 else 355 throw new ParseException(str.filename + " " + str.line + ": " + msg); 356 } 357 358 public void unexpected(Token tok) { 360 die ("unexpected token: " + tok); } 362 363 private static boolean isIdChar(char c) { 364 return c=='/' || c=='_' || c=='<' || c=='>' || c=='$' || c=='*' || 365 Character.isLetterOrDigit(c); 366 } 367 368 373 private void id(StringBuffer text) { 374 if (isIdChar(peekchar())) { 375 text.append(readchar()); 376 while (true) 377 if (isIdChar(peekchar())) 378 text.append(readchar()); 379 else 380 return; 381 } else 382 die("unexpected char '" + (char)peekch() + "'"); 383 } 385 386 private void expectCh(char ch) { 387 if (peekch() != ch) 388 die ("expected: '" + ch + "'"); 389 } 390 391 private void matchCh (StringBuffer text, char ch) { 392 expectCh(ch); 393 text.append( (char) readch() ); 394 } 395 396 400 private void type(StringBuffer text) { 401 while (peekch() == '[') { 402 text.append((char) readch()); 403 } 404 switch (peekch()) { 405 case 'B': case 'C': case 'D': case 'F': case 'I': 406 case 'J': case 'S': case 'Z': case 'V': 407 text.append((char) readch()); break; 409 case 'L': text.append((char) readch()); 411 id(text); 412 matchCh(text, ';'); 413 break; 414 default: 415 die("unexpected char '" + (char)peekch() + "'"); 416 } 417 } 418 419 434 435 440 private int number(StringBuffer text) { 441 boolean isfloat = false, hex = false, negative = false; 442 int digits_so_far = 0; 443 445 for (;; text.append(readchar())) { 446 int ch = peekch(); 447 if (ch >= '0' && ch <= '9') { 448 digits_so_far++; 449 } else if (ch == 'x' && digits_so_far==1 && !hex && !isfloat) { 450 hex = true; 451 } else if (ch == '.' && !hex && !isfloat) { 452 isfloat = true; 453 digits_so_far = 0; 454 } else if (ch == '-' && digits_so_far==0 && !isfloat && !negative){ 455 negative = true; 456 } else if (digits_so_far == 0) { 457 die("unexpected char '" + (char)ch + "'"); 458 } else { 459 return isfloat ? Token.FLOAT : Token.INT; 460 } 461 } 462 } 463 464 469 private void string(StringBuffer text, char quote) { 470 push(ST_STRING); 471 expectCh(quote); 472 readch(); 473 while (true) { 474 int ch = readch(), ch2; 475 476 if (ch == quote) { 477 pop(); 478 return; 479 } 480 switch (ch) { 481 case EOFCH: 482 die("unexpected end of file"); 483 case '\\': 484 ch2 = readch(); 485 switch (ch2) { 486 case EOFCH: 487 die("unexpected end of file"); 488 case 'n': 489 text.append( '\n' ); 490 break; 491 case 't': 492 text.append( '\t' ); 493 break; 494 case 'r': 495 text.append( '\r' ); 496 break; 497 default: 498 text.append( (char) ch2 ); 499 } 500 break; 501 default: 502 text.append( (char) ch ); 503 } 504 } 505 } 506 507 private void descriptor(StringBuffer text) { 508 matchCh(text, '('); 509 while (peekch() != ')') { 510 type(text); 511 } 512 matchCh(text, ')'); 513 type(text); 514 } 515 516 517 private void matchString (StringBuffer text, String s) { 518 for (int i = 0; i < s.length(); i++) 519 matchCh(text, s.charAt(i)); 520 } 521 522 523 private Token read_token() { 524 bigdo: 525 do { 526 if (state != ST_OPT) skip_ws(); 527 528 531 if ( laCh(1) == '/' && laCh(2) == '/' ) { 532 push(ST_COMMENT); 533 readch(); readch(); 534 while (true) 535 switch(readch()) { 536 case EOFCH: 537 die("unexpected end of file"); 538 case '\n': 539 pop(); 540 continue bigdo; 541 } 542 } 543 544 547 if (laCh(1) == '/' && laCh(2) == '*') { 548 readch(); readch(); 549 for (boolean last_was_star = false;;) { 550 int ch = readch(); 551 if (ch == EOFCH) die ("unexpected end of file"); 552 if (last_was_star && ch=='/') continue bigdo; 553 last_was_star = ch == '*'; 554 } 555 } 556 557 558 StringBuffer text = new StringBuffer (); 559 switch(state) { 560 case ST_TAG: 561 if (peekch() == EOFCH) return EOF; 562 if (peekch() == ';') return new Token(readch()); 563 if (! Character.isLetter(peekchar()) && peekchar()!='_') 564 die ("unexpected char: '" + peekchar() + "'"); 565 state = ST_DASH; 566 while (true) { 567 text.append( (char) readch() ); 568 if (! Character.isLetter(peekchar()) && peekchar()!='_') 569 return new Token(Token.TAG, text.toString()); 570 } 571 572 case ST_DASH: 573 if (peekch() != '-') { 575 state = ST_NORMAL; 576 return END_OF_OPTS; 577 } 578 readch(); 579 if (border()) 580 die("at least on option expected after a dash"); 581 state = ST_OPT; 582 584 case ST_OPT: 585 if (border()) { 586 state = ST_DASH; 587 continue bigdo; 588 } 589 return new Token(readch()); 590 591 case ST_ASM_ARG: 592 case ST_NORMAL: 593 if (peekch() == EOFCH) return EOF; 594 if ((peekch() >= '0' && peekch() <= '9') || peekch() == '-') 595 try { 596 switch(number(text)) { 597 case Token.INT: return new Token(Token.INT, Long.parseLong(text.toString())); 598 case Token.FLOAT: return new Token(Token.FLOAT, Double.parseDouble(text.toString())); 599 } 600 } catch (NumberFormatException e) { 601 die ("bad number: " + e.getMessage()); 602 } 603 if (isIdChar(peekchar())) { 604 id(text); 605 return new Token(Token.NAME, text.toString()); 606 } 607 608 if (peekchar() == '[') { 609 type(text); 611 return new Token(Token.NAME, text.toString()); 612 } 613 614 if (peekchar() == '@') { 615 text.append(readchar()); 616 skip_ws(); 617 if (peekchar()==EOFCH) die ("unexpected end of file"); 618 while (true) { 619 if (Character.isWhitespace(peekchar()) || 620 peekch()==EOFCH) break; 621 text.append( readchar() ); 622 } 623 return new Token(Token.NAME, text.toString()); 624 } 625 626 627 else if ( peekch() == '.' ) return new Token( readch() ); 628 else if ( peekch() == ';' ) return new Token( readch() ); 629 else if ( peekch() == '\\') return new Token( readch() ); 630 else if ( peekch() == ':' ) return new Token( readch() ); 631 else if ( peekch() == '}' ) return new Token( readch() ); 632 else if ( peekch() == '(' ) return new Token( readch() ); 633 else if ( peekch() == ')' ) return new Token( readch() ); 634 else if ( peekch() == '"' || peekch() == '\'') { 635 string(text, peekchar()); 636 return new Token(Token.STRING, text.toString()); 637 } else 638 die("unexpected char '" + (char)readch() + "'"); 639 640 case ST_TYPE: 641 if (peekch() == EOFCH) return EOF; 642 else if ( peekch() == '}' ) return new Token( readch() ); 643 else if ( peekch() == ';' ) return new Token( readch() ); 644 if (peekch() == '(') { 645 descriptor(text); 646 return new Token(Token.DESCRIPTOR, text.toString()); 647 } else { 648 type(text); 649 return new Token(Token.TYPE, text.toString()); 650 } 651 652 653 case ST_STRING: 654 if (peekch() == EOFCH) return EOF; 655 if (peekch() == ';') return new Token( readch() ); 656 if ( peekch() == '"' || peekch() == '\'') { 657 string(text, peekchar()); 658 return new Token(Token.STRING, text.toString()); 659 } 660 while (true) { 661 text.append( readchar() ); 662 if (peekch()==EOFCH || Character.isWhitespace(peekchar()) || 663 peekch()==';') 664 return new Token(Token.STRING, text.toString()); 665 } 666 667 case ST_ASM: 668 if (peekch() == EOFCH) return EOF; 669 if (peekch() == ';') return new Token( readch() ); 670 if (peekch() == '}') return new Token( readch() ); 671 if (peekch() == '{') return new Token( readch() ); 672 if (peekch() == ':') die ("colon wihtout a label"); 673 if ( peekch() == '"' || peekch() == '\'') { 674 string(text, peekchar()); 675 return new Token(Token.TAG, text.toString()); 676 } 677 while (true) { 678 text.append( readchar() ); 679 if (peekch() == ':') { 680 readch(); 681 return new Token(Token.LABEL, text.toString()); 682 } if (Character.isWhitespace(peekchar())) { 683 skip_ws(); 684 if (peekch() == ':') { 685 readch(); 686 return new Token(Token.LABEL, text.toString()); 687 } else 688 return new Token(Token.TAG, text.toString()); 689 } 690 if (peekch()==EOFCH || peekch()==';') 691 return new Token(Token.TAG, text.toString()); 692 } 693 694 695 725 726 727 728 } 729 730 throw new RuntimeException ("internal error " + state); 731 } while (true); 732 } 733 734 735 public Token match(int type) { 737 Token tok = read(); 738 if (tok.type != type) 739 unexpected(tok); 740 return tok; 741 } 742 743 744 759 760 761 762 public void term() { 764 if (la(1).type == Token.EOF || la(1).type == '}') 765 return; 766 match(';'); 767 } 768 769 770 public String parse_name() { 772 String s = match(Token.NAME).text; 773 return s; 774 } 775 776 public String parse_string() { 778 return match(Token.STRING).text; 779 } 780 781 public Descriptor parse_descriptor() { 783 push(ST_TYPE); 784 String in = match(Token.DESCRIPTOR).text; 785 Descriptor d = new Descriptor(in); 786 pop(); 787 return d; 788 } 789 790 public Type parse_type() { 792 push(ST_TYPE); 793 String in = match(Token.TYPE).text; 794 Type t = new Type(in); 795 pop(); 796 return t; 797 } 798 799 public long parse_long() { 801 long l = match(Token.INT).l; 802 return l; 803 } 804 805 public int parse_int() { 807 return (int) parse_long(); 808 } 809 810 public double parse_double() { 812 return match(Token.FLOAT).d; 813 } 814 815 816 822 823 public int parse_flags(int ok) { 825 int ret = 0; 826 while (true) { 827 Token tok = peek(); 828 if (tok.type != Token.NAME && tok.type != Token.TAG) return ret; 829 830 if (tok.text.equals("public") && 831 ((Util.ACC_PUBLIC & ok) != 0)) 832 ret |= Util.ACC_PUBLIC; 833 else if(tok.text.equals("private") && 834 ((Util.ACC_PRIVATE & ok) != 0)) 835 ret |= Util.ACC_PRIVATE; 836 else if(tok.text.equals("protected") && 837 ((Util.ACC_PROTECTED & ok) != 0)) 838 ret |= Util.ACC_PROTECTED; 839 else if(tok.text.equals("static") && 840 ((Util.ACC_STATIC & ok) != 0)) 841 ret |= Util.ACC_STATIC; 842 else if(tok.text.equals("final") && 843 ((Util.ACC_FINAL & ok) != 0)) 844 ret |= Util.ACC_FINAL; 845 else if(tok.text.equals("synchronized") && 846 ((Util.ACC_SYNCHRONIZED & ok) != 0)) 847 ret |= Util.ACC_SYNCHRONIZED; 848 else if(tok.text.equals("super") && 849 ((Util.ACC_SUPER & ok) != 0)) 850 ret |= Util.ACC_SUPER; 851 else if(tok.text.equals("native") && 852 ((Util.ACC_NATIVE & ok) != 0)) 853 ret |= Util.ACC_NATIVE; 854 else if(tok.text.equals("abstract") && 855 ((Util.ACC_ABSTRACT & ok) != 0)) 856 ret |= Util.ACC_ABSTRACT; 857 else if(tok.text.equals("strict") && 858 ((Util.ACC_STRICT & ok) != 0)) 859 ret |= Util.ACC_STRICT; 860 else if(tok.text.equals("volatile") && 861 ((Util.ACC_VOLATILE & ok) != 0)) 862 ret |= Util.ACC_VOLATILE; 863 else if(tok.text.equals("transient") && 864 ((Util.ACC_TRANSIENT & ok) != 0)) 865 ret |= Util.ACC_TRANSIENT; 866 else if(tok.text.equals("interface") && 867 ((Util.ACC_INTERFACE & ok) != 0)) 868 ret |= Util.ACC_INTERFACE; 869 else if (tok.text.equals("endflags")) { 870 read(); 871 return ret; 872 } else 873 return ret; 874 875 read(); 876 } 877 } 878 879 880 public Descriptor parseOptDescriptor(String cname, String mname) throws ClassFileException { 882 if (la(1).type == ':') { 883 read(); 884 return parse_descriptor(); 885 } 886 ClassInfo cr = Jbet.loader.getClass(cname); 887 MethodInfo mi = cr.findMethod(mname); 888 if (mi == null) die 889 ("cannot determine type of " + cname + "." + mname); 890 return mi.descriptor; 891 } 892 893 public Type parseOptType(String cname, String fname) throws ClassFileException { 895 if (la(1).type == ':') { 896 read(); 897 return parse_type(); 898 } 899 ClassInfo cr = Jbet.loader.getClass(cname); 900 FieldInfo mi = cr.findField(fname); 901 if (mi == null) die 902 ("cannot determine type of " + cname + "." + fname); 903 return mi.type; 904 } 905 906 public String parse_optclassname (String default_class) { 908 if (default_class != null && peek().type != Token.NAME) 909 return default_class; 910 else 911 return parse_name(); 912 } 913 914 private static final int PT_TYPE = 0x1; 915 private static final int PT_DESCRIPTOR = 0x2; 916 917 public Thing parse_thing (String defclass) { 919 return parse_thing (defclass, PT_DESCRIPTOR); 920 } 921 922 public Thing parse_thing(String defclass, int flags) { 924 String p_class = null; 925 String p_name = null; 926 Descriptor p_d = null; 927 Type p_t = null; 928 929 if (defclass != null && peek().type != Token.NAME) 930 p_class = defclass; 931 else 932 p_class = parse_name(); 933 if (peek().type == '.') { 934 read(); 935 p_name = parse_name(); 936 if ( (flags & (PT_TYPE | PT_DESCRIPTOR)) == 0) 937 return new Thing (p_class, p_name, p_t, p_d); 938 if (peek().type == ':') { 939 read(); 940 push(ST_TYPE); 941 if (peek().type == Token.TYPE && (flags & PT_TYPE) != 0 ) 942 p_t = parse_type(); 943 if (peek().type == Token.DESCRIPTOR && 944 (flags & PT_DESCRIPTOR) != 0) 945 p_d = parse_descriptor(); 946 else 947 unexpected(read()); 948 pop(); 949 } 950 } 951 952 return new Thing (p_class, p_name, p_t, p_d); 953 } 954 955 962 public Object getThing(String defclass) throws ClassFileException, ElementNotFoundException { 963 Thing t = parse_thing(defclass); 964 return Jbet.loader.getThing(t.cls, t.name, t.desc); 965 } 966 967 public MethodInfo getMethod(String defclass) throws ClassFileException, ElementNotFoundException { 968 Object thing = getThing(defclass); 969 if (thing instanceof MethodInfo) 970 return (MethodInfo) thing; 971 throw new ParseException ("expected a method"); 972 } 973 974 public ClassInfo getClass(String defclass) throws ClassFileException, ElementNotFoundException { 975 String cname; 976 if (defclass != null && peek().type != Token.NAME) 977 cname = defclass; 978 else 979 cname = parse_name(); 980 return Jbet.loader.getClass(cname); 981 } 982 983 984 private void findClasses(Collection classes, String dirname, File dir, 985 String packagePrefix, boolean sense) throws ClassFileException { 986 File [] files = dir.listFiles(); 987 for (int i = 0; i < files.length; i++) { 988 if (files[i].isDirectory()) 989 findClasses(classes, 990 dirname + File.separator + files[i].getName(), 991 files[i], 992 packagePrefix + "/" + files[i].getName(), sense); 993 else if (files[i].getName().endsWith(".class")) { 994 Util.addOrRemove(classes, "@" + dirname + File.separator + files[i].getName(), sense); 995 } 996 } 997 } 998 999 1003 1004 public ClassInfo [] getClasses() throws ClassFileException { 1005 Vector classes = new Vector(); 1006 getClasses(classes); 1007 ClassInfo [] ret = new ClassInfo [ classes.size() ]; 1008 classes.toArray(ret); 1009 return ret; 1010 } 1011 1012 public void getClassNames (Collection classes) throws ClassFileException { 1013 getClassNames(classes, true); 1014 } 1015 1016 public void getClassNames (Collection classes, boolean sense) throws ClassFileException { 1017 while (peek().type == Token.NAME) { 1018 String name = parse_name(); 1019 if (name.startsWith("@") && name.endsWith("/*")) { 1020 String dirname = name.substring(1, name.length()-2 ); 1021 findClasses(classes,dirname, new File(dirname), "", sense); 1022 } else if (name.endsWith("/*")) { 1023 String packname = name.substring(0, name.length()-2); 1024 Jbet.loader.findPackageClasses(packname, classes, sense); 1025 } else if (name.equals("*")) { 1026 Jbet.loader.findPackageClasses("", classes, sense); 1027 } else 1028 classes.add( name ); 1029 } 1030 if (peek().type == '\\') { 1031 read(); 1032 getClassNames (classes, false); 1033 } 1034 } 1035 1036 public void getClasses (Collection classes) throws ClassFileException { 1037 getClasses(classes, Jbet.loader); 1038 } 1039 1040 public void getClasses (Collection classes, 1041 ClassFinder f) throws ClassFileException { 1042 Vector v = new Vector(); 1043 getClassNames(v); 1044 for (int i = 0; i < v.size(); i++) { 1045 String name = (String ) v.elementAt(i); 1046 classes.add( f.findClass(name) ); 1047 } 1048 } 1049 1050 1051 1060 public Thing parse_element_with_default (String def, boolean opttype) 1061 throws Exception { 1062 1063 String p_class = null; 1064 String p_name = null; 1065 String p_type; 1066 1067 p_type = null; 1068 if ( this.la(1).type == Token.DEFAULT || 1069 this.la(1).type == Token.DONOR || 1070 ( this.la(1).type == Token.NAME && 1071 ( this.la(2).type == '.' || this.la(2).type == '$' ))) { 1072 p_class = this.parse_name(); this.match('.'); 1074 } else { 1075 if (def == null) 1076 this.die("you must provide a classname"); 1077 else 1078 p_class = def; 1079 } 1080 p_name = this.parse_name(); 1081 1082 if (!opttype) return new Thing (p_class, p_name, null); 1083 1084 if (this.la(1).type == ':') { 1085 this.read(); 1086 this.push(ST_TYPE); 1087 p_type = this.match(Token.DESCRIPTOR).text; 1088 this.pop(); 1089 } 1090 1091 return new Thing (p_class, p_name, p_type); 1092 } 1093 1094 1095 1096} 1097 | Popular Tags |