1 22 23 package org.aspectj.debugger.base; 24 25 import org.aspectj.debugger.request.*; 26 import java.util.*; 27 28 29 37 38 public class Parser { 40 private CommandReceiver debugger; 41 private StringTokenizer tok; 42 private Request lastRequest; 43 private String command; 44 private String lastCommand = ""; 45 46 private final static String [] commands = { 47 "break", 48 "catch", 49 "class", 50 "classes", 51 "classpath", 52 "clear", 53 "connect", 54 "cont", 55 "deport", 56 "dir", 57 "down", 58 "dump", 59 "eval", 60 "exclude", 61 "exit", 62 "fields", 63 "help", 64 "ignore", 65 "import", 66 "interrupt", 67 "kill", 68 "list", 69 "locals", 70 "lock", 71 "ls", 72 "methods", 73 "monitor", 74 "next", 75 "object", 76 "print", 77 "pwd", 78 "quit", 79 "read", 80 "resume", 81 "run", 82 "set", 83 "step", 84 "stepi", 85 "stop", 86 "suspend", 87 "thread", 88 "threadgroup", 89 "threadgroups", 90 "threadlocks", 91 "threads", 92 "tostring", 93 "trace", 94 "unmonitor", 95 "untrace", 96 "unwatch", 97 "up", 98 "use", 99 "version", 100 "view", 101 "watch", 102 "where", 103 "workingdir", 104 "?", 105 }; 106 107 private static Map aliases = new HashMap(); 108 static { 109 String [] strings = { 110 "break", "b", 111 "cont", "c", 112 "down", "d", 113 "help", "h", 114 "list", "l", 115 "monitor", "m", 116 "next", "n", 117 "quit", "q", 118 "read", "r", 119 "step", "s", 120 "stepi", "si", 121 "step up", "su", 122 "up", "u", 123 "where", "w", 124 }; 125 for (int i = 0; i < strings.length; i += 2) { 126 aliases.put(strings[i+1], strings[i]); 127 } 128 } 129 private String alias(String line) { 130 Object alias = aliases.get(line); 131 return alias != null ? alias + "" : line; 132 } 133 134 private static String [] noVmCommands = { 135 "catch", 136 "clear", 137 "dir", 138 "exit", 139 "help", 140 "ignore", 141 "import", 142 "list", 143 "ls", 144 "pwd", 145 "quit", 146 "read", 147 "run", 148 "sourcepath", 149 "stop", 150 "unwatch", 151 "use", 152 "version", 153 "watch", 154 "?", 155 }; 156 157 public final static String THREAD = "Thread number not specified."; 158 public final static String KILL = "Usage: kill <thread id> <throwable>"; 159 public final static String PRINT = "No objects specified."; 160 public final static String DUMP = PRINT; 161 public final static String EVAL = PRINT; 162 public final static String SET = "Usage: set <lvalue> = <expr>"; 163 public final static String CLASS = "No class specified."; 164 public final static String METHODS = CLASS; 165 public final static String FIELDS = CLASS; 166 public final static String THREADGROUP = "Threadgroup name not specified."; 167 public final static String CATCH = "Threadgroup name not specified."; 168 public final static String WATCH = "watch [access|all] ..."; 169 public final static String UNWATCH = "unwatch [access|all] ..."; 170 public final static String UNMONITOR = "usage: unmonitor <monitor#>"; 171 public final static String READ = "usage: read <command-filename>"; 172 public final static String UNKOWN_COMMAND = "Unkown command, type 'help' for more help"; 173 public final static String CLASS_METHOD = "<class>.<method>"; 174 public final static String SOURCE_LINE = "<source>:<line>"; 175 public final static String SOURCE_LINE_NO_NUMBER = "<source>:<line> (<line was not a number)"; 176 public final static String CLASS_LINE = "<class>:<line>"; 177 public final static String CLASS_LINE_NO_NUMBER = "<class>:<line> (<line was not a number)"; 178 public final static String END_OF_LINE = "Unexpected end of line"; 179 public final static String EXPECTING_NUMBER = "Expecting a number"; 180 public final static String IMPORT = "Usage: import <path>"; 181 public final static String DEPORT = "Usage: deport <path>"; 182 183 private CommandCompletor completor = new CommandCompletor(commands); 184 185 public Parser(CommandReceiver debugger) { 186 this.debugger = debugger; 187 } 188 189 public Object parse(String line) throws ParseException, 190 NoVMException, 191 DebuggerException { 192 Object result; 193 command = alias(line); 194 tok = new StringTokenizer(line); 195 196 if (!tok.hasMoreTokens()) { 197 return null; 199 } 200 201 String first = tok.nextToken().trim(); 202 first = completor.getCommand(first); 203 204 checkRunningVM(first); 205 206 if (first.endsWith("!")) { 207 first = first.substring(0, first.length()-1); 209 } 210 211 if (first.equals("threads")) { 213 String threadGroup = question(); 214 result = debugger.threadsCommand(threadGroup); 215 216 } else if (first.equals("thread")) { 218 String thread = next(THREAD); 219 result = debugger.threadCommand(thread); 220 221 } else if (first.equals("suspend")) { 223 List threads = listStar(); 224 result = debugger.suspendCommand(threads); 225 226 } else if (first.equals("resume")) { 228 List threads = listStar(); 229 result = debugger.resumeCommand(threads); 230 231 } else if (first.equals("where")) { 233 String thread = question(); 234 result = debugger.whereCommand(thread); 235 236 } else if (first.equals("up")) { 238 int num = integerStar(); 239 if (num == -1) num = 1; 240 result = debugger.upCommand(num); 241 242 } else if (first.equals("down")) { 244 int num = integerStar(); 245 if (num == -1) num = 1; 246 result = debugger.downCommand(num); 247 248 } else if (first.equals("kill")) { 250 String thread = next(KILL); 251 String expr = rest(KILL); 252 result = debugger.killCommand(thread, expr); 253 254 } else if (first.equals("interrupt")) { 256 String thread = next(); 257 result = debugger.interruptCommand(thread); 258 259 } else if (first.equals("print")) { 261 String expr = rest(PRINT); 262 result = debugger.printCommand(expr); 263 264 } else if (first.equals("dump")) { 266 String expr = rest(DUMP); 267 result = debugger.dumpCommand(expr); 268 269 } else if (first.equals("eval")) { 271 String expr = rest(EVAL); 272 result = debugger.evalCommand(expr); 273 274 } else if (first.equals("set")) { 276 String lvalue = ident(SET); 277 String eq = next(SET); 278 String expr = ""; 279 if (eq.indexOf("=") == -1) { 280 expr = eq; 281 } else { 282 expr = rest(SET); 283 } 284 result = debugger.setCommand(lvalue, expr); 285 286 } else if (first.equals("locals")) { 288 result = debugger.localsCommand(); 289 290 } else if (first.equals("classes")) { 292 result = debugger.classesCommand(); 293 294 } else if (first.equals("class")) { 296 String classID = next(CLASS); 297 result = debugger.classCommand(classID); 298 299 } else if (first.equals("methods")) { 301 String classID = next(METHODS); 302 result = debugger.methodsCommand(classID); 303 304 } else if (first.equals("fields")) { 306 String classID = next(FIELDS); 307 result = debugger.fieldsCommand(classID); 308 309 } else if (first.equals("threadgroups")) { 311 result = debugger.threadGroupsCommand(); 312 313 } else if (first.equals("threadgroup")) { 315 String threadgroup = next(THREADGROUP); 316 result = debugger.threadGroupCommand(threadgroup); 317 318 } else if (first.equals("stop") || 320 first.equals("break")) { 321 result = stop(restStar()); 322 323 } else if (first.equals("clear")) { 325 result = clear(restStar()); 326 327 } else if (first.equals("catch")) { 329 String classID = next(CATCH); 330 result = debugger.catchCommand(classID); 331 332 } else if (first.equals("ignore")) { 334 String classID = next(); 335 result = debugger.ignoreCommand(classID); 336 337 } else if (first.equals("watch")) { 339 String accessOrAll = next(WATCH); 340 ClassMethod cm = classMethod(rest(WATCH)); 341 if (accessOrAll.equals("access")) { 342 result = debugger.watchAccessCommand(cm.className, cm.methodName); 343 } else if (accessOrAll.equals("all")) { 344 result = debugger.watchAllCommand(cm.className, cm.methodName); 345 } else { 346 throw new SyntaxException(WATCH); 347 } 348 349 } else if (first.equals("unwatch")) { 351 String accessOrAll = next(UNWATCH); 352 ClassMethod cm = classMethod(rest(UNWATCH)); 353 if (accessOrAll.equals("access")) { 354 result = debugger.unwatchAccessCommand(cm.className, cm.methodName); 355 } else if (accessOrAll.equals("all")) { 356 result = debugger.unwatchAllCommand(cm.className, cm.methodName); 357 } else { 358 throw new SyntaxException(UNWATCH); 359 } 360 361 } else if (first.equals("trace")) { 363 eat("methods"); 364 String thread = next(); 365 result = debugger.traceMethodsCommand(thread); 366 367 } else if (first.equals("untrace")) { 369 eat("methods"); 370 String thread = next(); 371 result = debugger.untraceMethodsCommand(thread); 372 373 } else if (first.equals("step")) { 375 if (star().equals("up")) { 376 result = debugger.stepUpCommand(); 377 } else { 378 result = debugger.stepCommand(); 379 } 380 381 } else if (first.equals("stepi")) { 383 result = debugger.stepiCommand(); 384 385 } else if (first.equals("next")) { 387 result = debugger.nextCommand(); 388 389 } else if (first.equals("cont")) { 391 result = debugger.contCommand(); 392 393 } else if (first.equals("exclude")) { 395 List classes = listStar(); 396 result = debugger.excludeCommand(classes); 397 398 } else if (first.equals("classpath")) { 400 result = debugger.classpathCommand(); 401 402 } else if (first.equals("lock")) { 404 String expr = rest(); 405 result = debugger.lockCommand(expr); 406 407 } else if (first.equals("threadlocks")) { 409 String thread = next(); 410 result = debugger.threadlocksCommand(thread); 411 412 } else if (first.equals("!!")) { 414 System.err.println("lastCommand=" + lastCommand); 415 result = debugger.bangBangCommand(lastCommand); 416 417 } else if (first.equals("help") || first.equals("?")) { 419 result = debugger.helpCommand(); 420 421 } else if (first.equals("version")) { 423 result = debugger.versionCommand(); 424 425 } else if (first.equals("exit") || first.equals("quit")) { 427 result = debugger.quitCommand(); 428 429 } else if (first.equals("run")) { 431 Options opts = debugger.getOptions(); 432 opts.fill(restStar()); 433 result = debugger.runCommand(opts); 434 435 } else if (first.equals("connect")) { 437 result = debugger.connectCommand(); 438 439 } else if (first.equals("use")) { 441 String sourcePath = restStar(); 442 result = debugger.useCommand(sourcePath); 443 444 } else if (first.equals("workingdir")) { 446 String workingdirPath = restStar(); 447 result = debugger.workingdirCommand(workingdirPath); 448 } else if (first.equals("list")) { 450 String sourceName = star(); 451 int startLine = -1; 452 int endLine = -1; 453 if (sourceName.equals("")) { 454 mandateRunningVM("list"); 455 result = debugger.listCommand(); 456 } else { 457 if (isNumber(sourceName)) { 458 startLine = Integer.parseInt(sourceName); 459 } else { 460 startLine = integerStar(); 461 } 462 endLine = integerStar(); 463 if (startLine == -1) { 464 result = debugger.listCommand(sourceName); 465 } else if (endLine == -1) { 466 result = debugger.listCommand(sourceName, startLine); 467 } else { 468 result = debugger.listCommand(sourceName, startLine, endLine); 469 } 470 } 471 472 } else if (first.equals("monitor")) { 474 String command = restStar(); 475 if (command.equals("")) { 476 result = debugger.monitorCommand(); 477 } else { 478 command = completor.getCommand(command); 479 result = debugger.monitorCommand(command); 480 } 481 482 } else if (first.equals("unmonitor")) { 484 int number = integer(rest(UNMONITOR), UNMONITOR); 485 result = debugger.unmonitorCommand(number); 486 487 } else if (first.equals("read")) { 489 String fileName = rest(READ); 490 result = debugger.readCommand(fileName); 491 492 } else if (first.equals("import")) { 494 String path = rest(IMPORT); 495 result = debugger.importCommand(path); 496 497 } else if (first.equals("deport")) { 499 String path = rest(DEPORT); 500 result = debugger.deportCommand(path); 501 502 } else if (first.equals("view")) { 504 String source = rest(); 505 result = debugger.viewCommand(source); 506 } else if (first.equals("tostring")) { 508 result = debugger.tostringCommand(); 509 } else if (first.equals("pwd")) { 511 result = debugger.pwdCommand(); 512 } else if (first.equals("ls") || first.equals("dir")) { 514 result = debugger.lsCommand(rest()); 515 } 516 517 else { 519 throw new ParseException(UNKOWN_COMMAND); 520 } 521 522 lastCommand = command; 523 524 return result; 525 } 526 527 private boolean equals(String first, String str) { 528 return first.equalsIgnoreCase(str); 529 } 530 531 private void mandateRunningVM(String command) throws ParseException { 532 checkRunningVM(command, true); 533 } 534 private void checkRunningVM(String first) throws ParseException { 535 checkRunningVM(first, false); 536 } 537 private void checkRunningVM(String first, boolean force) throws ParseException { 538 if (((Debugger) debugger).isRunning()) { 539 return; 540 } 541 if (!force) { 542 if (debugger.getOptions().isSet("extra")) { 543 return; 544 } 545 int N = noVmCommands.length; 546 for (int i = 0; i < N; i++) { 547 if (noVmCommands[i].equals(first)) { 548 return; 549 } 550 } 551 } 552 String msg = "Command '" + first 553 + "' is not valid until the VM is started " 554 + "with the 'run' command"; 555 throw new ParseException(msg); 556 } 557 558 private boolean isNumber(String str) { 559 try { 560 Integer.parseInt(str); 561 return true; 562 } catch (NumberFormatException e) { 563 } 564 return false; 565 } 566 567 private String star() { 568 if (tok.hasMoreTokens()) { 569 return tok.nextToken().trim(); 570 } 571 return ""; 572 } 573 574 private String restStar() { 575 if (tok.hasMoreTokens()) { 576 return tok.nextToken("").trim(); 577 } 578 return ""; 579 } 580 581 private String eat(String str) throws ParseException { 582 if (tok.hasMoreTokens()) { 583 return next(); 584 } 585 throw new ParseException("Expecting '" + str + "'; found an end-of-line"); 586 } 587 588 private Object stop(String theRest) 589 throws ParseException, NoVMException, DebuggerException { 590 return parseBreakpoint(theRest, true); 591 } 592 593 private Object clear(String theRest) 594 throws ParseException, NoVMException, DebuggerException { 595 return parseBreakpoint(theRest, false); 596 } 597 598 private Object parseBreakpoint(String theRest, boolean isStop) 599 throws ParseException, NoVMException, DebuggerException { 600 try { 601 String rest = theRest; 602 rest = rest.trim(); 603 if (rest.equals("") || rest.length() == 0) { 604 return isStop ? debugger.stopCommand() : debugger.clearCommand(); 605 } else if (rest.startsWith("at ") || 606 rest.startsWith("in ") || 607 rest.startsWith("on ")) { 608 rest = rest.substring(3).trim(); 609 theRest = rest; 610 } 611 612 String classOrSource = ""; 613 int index = 0; 614 boolean isMethod = true; 615 for (int i = rest.length()-1; i >= 0; i--) { 616 if (isOneOf(rest.charAt(i), ":; ")) { 617 index = i; 618 isMethod = false; 619 break; 620 } 621 if (rest.charAt(i) == '(') { 622 index = i; 623 isMethod = true; 624 break; 625 } 626 } 627 if (index > 0) { 628 classOrSource = rest.substring(0, index).trim(); 629 } else { 630 classOrSource = rest; 631 } 632 if (index < rest.length()) { 633 rest = rest.substring(index).trim(); 634 } else { 635 rest = ""; 636 } 637 isMethod |= rest.length() == 0 || rest.startsWith("("); 638 if (isMethod) { 639 int ilastDot = classOrSource.length() - 1; 640 while (ilastDot > 0) { 641 if (classOrSource.charAt(ilastDot) == '.') { 642 break; 643 } 644 ilastDot--; 645 } 646 String className = theRest.substring(0, ilastDot); 647 String methodProto = theRest.substring(ilastDot+1); 648 return isStop 649 ? debugger.stopInCommand (className, methodProto) 650 : debugger.clearInCommand(className, methodProto); 651 } else { 652 if (isOneOf(rest.charAt(0), ":;,")) { 653 rest = rest.substring(1); 654 } 655 if (classOrSource.endsWith(".java")) { 656 int integer = integer(rest.trim()); 657 return isStop 658 ? debugger.stopOnCommand (classOrSource, integer) 659 : debugger.clearOnCommand(classOrSource, integer); 660 } else { 661 int integer = integer(rest); 662 return isStop 663 ? debugger.stopAtCommand (classOrSource, integer) 664 : debugger.clearAtCommand(classOrSource, integer); 665 } 666 } 667 } catch (IndexOutOfBoundsException ioobe) { 668 } 669 throw new ParseException("Unexpected command"); 670 } 671 672 673 private boolean isOneOf(char c, String s) { 674 for (int i = 0; i < s.length(); i++) { 675 if (c == s.charAt(i)) { 676 return true; 677 } 678 } 679 return false; 680 } 681 682 static class ClassMethod { 683 String className; 684 String methodName; 685 public ClassMethod(String className, String methodName) { 686 this.className = className; 687 this.methodName = methodName; 688 } 689 } 690 691 private ClassMethod classMethod(String rest) throws ParseException { 692 try { 693 return _classMethod(rest); 694 } catch (Exception e) { 695 } 696 throw new SyntaxException(CLASS_METHOD); 697 } 698 699 private ClassMethod _classMethod(String rest) throws ParseException { 700 int iparen = rest.indexOf("("); 701 String className = ""; 702 String methodName = ""; 703 int idot = -1; 704 if (iparen == -1) { 705 idot = rest.lastIndexOf("."); 706 } else { 707 idot = iparen; 708 while (idot > 0) { 709 if (rest.charAt(idot) == '.') { 710 break; 711 } 712 idot--; 713 } 714 } 715 if (idot == -1) { 716 throw new SyntaxException(CLASS_METHOD); 717 } 718 className = rest.substring(0, idot); 719 methodName = rest.substring(idot + 1); 720 return new ClassMethod(className, methodName); 721 } 722 723 static class SourceLine { 724 String sourceName; 725 int line; 726 public SourceLine(String sourceName, int line) { 727 this.sourceName = sourceName; 728 this.line = line; 729 } 730 } 731 732 private SourceLine sourceLine(String rest) throws ParseException { 733 StringTokenizer colonTok = new StringTokenizer(rest, ":"); 734 int icolon = rest.lastIndexOf(":"); 735 if (icolon == -1) { 736 throw new SyntaxException(SOURCE_LINE); 737 } 738 try { 739 String sourceName = rest.substring(0, icolon); 740 String lineName = rest.substring(icolon+1); 741 int line = Integer.parseInt(lineName); 742 return new SourceLine(sourceName, line); 743 } catch (NoSuchElementException e) { 744 throw new SyntaxException(SOURCE_LINE); 745 } catch (NumberFormatException nfe) { 746 throw new SyntaxException(SOURCE_LINE_NO_NUMBER); 747 } 748 } 749 750 static class ClassLine { 751 String className; 752 int line; 753 public ClassLine(String className, int line) { 754 this.className = className; 755 this.line = line; 756 } 757 } 758 759 private ClassLine classLine(String rest) throws ParseException { 760 StringTokenizer colonTok = new StringTokenizer(rest, ":"); 761 int icolon = rest.lastIndexOf(":"); 762 if (icolon == -1) { 763 throw new SyntaxException(SOURCE_LINE); 764 } 765 try { 766 String className = rest.substring(0, icolon); 767 String lineName = rest.substring(icolon+1); 768 int line = Integer.parseInt(lineName); 769 return new ClassLine(className, line); 770 } catch (NoSuchElementException e) { 771 throw new SyntaxException(CLASS_LINE); 772 } catch (NumberFormatException nfe) { 773 throw new SyntaxException(CLASS_LINE_NO_NUMBER); 774 } 775 } 776 777 private String dump() { 778 if (tok.hasMoreTokens()) { 779 String str = tok.nextToken("").trim(); 780 tok = new StringTokenizer(str); 781 return str; 782 } 783 return ""; 784 } 785 786 private String nextStar() { 787 if (tok.hasMoreTokens()) { 788 return tok.nextToken().trim(); 789 } 790 return ""; 791 } 792 793 private String next(String s) throws ParseException { 794 if (tok.hasMoreTokens()) { 795 return tok.nextToken().trim(); 796 } 797 throw new ParseException(s); 798 } 799 800 private String next() throws ParseException { 801 return next(END_OF_LINE); 802 } 803 804 private String question() { 805 if (tok.hasMoreTokens()) { 806 return tok.nextToken("").trim(); 807 } 808 return ""; 809 } 810 811 private String rest() throws ParseException { 812 return rest(END_OF_LINE); 813 } 814 815 private String rest(String s) throws ParseException { 816 if (tok.hasMoreTokens()) { 817 return tok.nextToken("").trim(); 818 } 819 throw new ParseException(s); 820 } 821 822 private List listStar() { 823 List list = new Vector(); 824 while (tok.hasMoreTokens()) { 825 list.add(tok.nextToken().trim()); 826 } 827 return list; 828 } 829 830 private int integer() throws ParseException { 831 return integer(rest()); 832 } 833 834 private int integer(String num) throws ParseException { 835 return integer(num, null); 836 } 837 838 private int integer(String rest, String msg) throws ParseException { 839 if (rest != null) { 840 try { 841 return Integer.parseInt(rest.trim()); 842 } catch (NumberFormatException e) { 843 } 844 } 845 throw new ParseException((msg == null ? "Expecting a number" : msg)); 846 } 847 848 private int integerStar() throws ParseException { 849 String next = nextStar(); 850 if (next.equals("")) { 851 return -1; 852 } 853 try { 854 return Integer.parseInt(next.trim()); 855 } catch (NumberFormatException e) { 856 } 857 throw new ParseException(EXPECTING_NUMBER); 858 } 859 860 private boolean ws(String s) { 861 for (int i = 0; i < s.length(); i++) { 862 if (Character.isWhitespace(s.charAt(i))) { 863 return true; 864 } 865 } 866 return false; 867 } 868 869 private String ident(String s) throws ParseException { 870 try { 871 return ident(); 872 } catch (ParseException e) {} 873 throw new ParseException(s); 874 } 875 876 private String ident() throws ParseException { 877 String token = next(); 878 if (!(Character.isJavaIdentifierStart(token.charAt(0)))) { 879 throw new InvalidIdentException(token); 880 } 881 for (int i = 1; i < token.length(); i++) { 882 char c = token.charAt(i); 883 if (!(Character.isJavaIdentifierPart(c)) && 884 c != '.' && 885 c != '[' && 886 c != ']') { 887 throw new InvalidIdentException(token); 888 } 889 } 890 return token; 891 } 892 893 public String command() { 894 return command; 895 } 896 897 class CommandCompletor { 898 String [] commands; 899 900 public CommandCompletor(String [] commands) { 901 this.commands = commands; 902 } 903 904 public String getCommand(String start) throws ParseException { 905 return getCommand(start, true); 906 } 907 908 public String getCommand(String start, boolean throwException) throws ParseException { 909 Object match = aliases.get(start); 910 if (match != null) { 911 return match + ""; 912 } 913 914 Vector matches = new Vector(); 915 for (int i = 0; i < commands.length; i++) { 916 if (commands[i].equals(start)) { 917 return start; 918 } else if (commands[i].startsWith(start)) { 919 matches.add(commands[i]); 920 } 921 } 922 if (matches.size() == 0) { 923 if (start.endsWith("!")) { 924 String str = getCommand(start.substring(0, start.length()-1), false); 925 if (str != null) return str+"!"; 926 else throwException = true; 927 } 928 if (throwException) 929 throw new ParseException("No command begins with the prefix '" + start + "'"); 930 else return null; 931 } else if (matches.size() > 1) { 932 if (throwException) { 933 String msg = "The prefix '" + start + "' has the possible completions:\n"; 934 Iterator iter = matches.iterator(); 935 while (iter.hasNext()) { 936 msg += "\t" + iter.next() + "\n"; 937 } 938 throw new ParseException(msg); 939 } 940 else return null; 941 } 942 return matches.get(0) + ""; 943 } 944 } 945 } 946 | Popular Tags |