1 /* Tree browser. 2 Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010 3 Free Software Foundation, Inc. 4 Contributed by Sebastian Pop <s.pop@laposte.net> 5 6 This file is part of GCC. 7 8 GCC is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free 10 Software Foundation; either version 3, or (at your option) any later 11 version. 12 13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 14 WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GCC; see the file COPYING3. If not see 20 <http://www.gnu.org/licenses/>. */ 21 22 #include "config.h" 23 #include "system.h" 24 #include "coretypes.h" 25 #include "tree.h" 26 #include "tree-pretty-print.h" 27 28 #define TB_OUT_FILE stdout 29 #define TB_IN_FILE stdin 30 #define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n") 31 #define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n") 32 33 /* Structures for handling Tree Browser's commands. */ 34 #define DEFTBCODE(COMMAND, STRING, HELP) COMMAND, 35 enum TB_Comm_code { 36 #include "tree-browser.def" 37 TB_UNUSED_COMMAND 38 }; 39 #undef DEFTBCODE 40 typedef enum TB_Comm_code TB_CODE; 41 42 struct tb_command { 43 const char *help_msg; 44 const char *comm_text; 45 size_t comm_len; 46 TB_CODE comm_code; 47 }; 48 49 #define DEFTBCODE(code, str, help) { help, str, sizeof(str) - 1, code }, 50 static const struct tb_command tb_commands[] = 51 { 52 #include "tree-browser.def" 53 }; 54 #undef DEFTBCODE 55 56 #define TB_COMMAND_LEN(N) (tb_commands[N].comm_len) 57 #define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text) 58 #define TB_COMMAND_CODE(N) (tb_commands[N].comm_code) 59 #define TB_COMMAND_HELP(N) (tb_commands[N].help_msg) 60 61 62 /* Next structure is for parsing TREE_CODEs. */ 63 struct tb_tree_code { 64 enum tree_code code; 65 const char *code_string; 66 size_t code_string_len; 67 }; 68 69 #define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 }, 70 #define END_OF_BASE_TREE_CODES \ 71 { LAST_AND_UNUSED_TREE_CODE, "@dummy", sizeof ("@dummy") - 1 }, 72 static const struct tb_tree_code tb_tree_codes[] = 73 { 74 #include "all-tree.def" 75 }; 76 #undef DEFTREECODE 77 #undef END_OF_BASE_TREE_CODES 78 79 #define TB_TREE_CODE(N) (tb_tree_codes[N].code) 80 #define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string) 81 #define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len) 82 83 84 /* Function declarations. */ 85 86 static long TB_getline (char **, long *, FILE *); 87 static TB_CODE TB_get_command (char *); 88 static enum tree_code TB_get_tree_code (char *); 89 static tree find_node_with_code (tree *, int *, void *); 90 static tree store_child_info (tree *, int *, void *); 91 static void TB_update_up (tree); 92 static tree TB_current_chain_node (tree); 93 static tree TB_prev_expr (tree); 94 static tree TB_next_expr (tree); 95 static tree TB_up_expr (tree); 96 static tree TB_first_in_bind (tree); 97 static tree TB_last_in_bind (tree); 98 static int TB_parent_eq (const void *, const void *); 99 static tree TB_history_prev (void); 100 101 /* FIXME: To be declared in a .h file. */ 102 void browse_tree (tree); 103 104 /* Static variables. */ 105 static htab_t TB_up_ht; 106 static VEC(tree,gc) *TB_history_stack; 107 static int TB_verbose = 1; 108 109 110 /* Entry point in the Tree Browser. */ 111 112 void 113 browse_tree (tree begin) 114 { 115 tree head; 116 TB_CODE tbc = TB_UNUSED_COMMAND; 117 ssize_t rd; 118 char *input = NULL; 119 long input_size = 0; 120 121 fprintf (TB_OUT_FILE, "\nTree Browser\n"); 122 123 #define TB_SET_HEAD(N) do { \ 124 VEC_safe_push (tree, gc, TB_history_stack, N); \ 125 head = N; \ 126 if (TB_verbose) \ 127 if (head) \ 128 { \ 129 print_generic_expr (TB_OUT_FILE, head, 0); \ 130 fprintf (TB_OUT_FILE, "\n"); \ 131 } \ 132 } while (0) 133 134 TB_SET_HEAD (begin); 135 136 /* Store in a hashtable information about previous and upper statements. */ 137 { 138 TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL); 139 TB_update_up (head); 140 } 141 142 while (24) 143 { 144 fprintf (TB_OUT_FILE, "TB> "); 145 rd = TB_getline (&input, &input_size, TB_IN_FILE); 146 147 if (rd == -1) 148 /* EOF. */ 149 goto ret; 150 151 if (rd != 1) 152 /* Get a new command. Otherwise the user just pressed enter, and thus 153 she expects the last command to be reexecuted. */ 154 tbc = TB_get_command (input); 155 156 switch (tbc) 157 { 158 case TB_UPDATE_UP: 159 TB_update_up (head); 160 break; 161 162 case TB_MAX: 163 if (head && (INTEGRAL_TYPE_P (head) 164 || TREE_CODE (head) == REAL_TYPE 165 || TREE_CODE (head) == FIXED_POINT_TYPE)) 166 TB_SET_HEAD (TYPE_MAX_VALUE (head)); 167 else 168 TB_WF; 169 break; 170 171 case TB_MIN: 172 if (head && (INTEGRAL_TYPE_P (head) 173 || TREE_CODE (head) == REAL_TYPE 174 || TREE_CODE (head) == FIXED_POINT_TYPE)) 175 TB_SET_HEAD (TYPE_MIN_VALUE (head)); 176 else 177 TB_WF; 178 break; 179 180 case TB_ELT: 181 if (head && TREE_CODE (head) == TREE_VEC) 182 { 183 /* This command takes another argument: the element number: 184 for example "elt 1". */ 185 TB_NIY; 186 } 187 else if (head && TREE_CODE (head) == VECTOR_CST) 188 { 189 /* This command takes another argument: the element number: 190 for example "elt 1". */ 191 TB_NIY; 192 } 193 else 194 TB_WF; 195 break; 196 197 case TB_VALUE: 198 if (head && TREE_CODE (head) == TREE_LIST) 199 TB_SET_HEAD (TREE_VALUE (head)); 200 else 201 TB_WF; 202 break; 203 204 case TB_PURPOSE: 205 if (head && TREE_CODE (head) == TREE_LIST) 206 TB_SET_HEAD (TREE_PURPOSE (head)); 207 else 208 TB_WF; 209 break; 210 211 case TB_IMAG: 212 if (head && TREE_CODE (head) == COMPLEX_CST) 213 TB_SET_HEAD (TREE_IMAGPART (head)); 214 else 215 TB_WF; 216 break; 217 218 case TB_REAL: 219 if (head && TREE_CODE (head) == COMPLEX_CST) 220 TB_SET_HEAD (TREE_REALPART (head)); 221 else 222 TB_WF; 223 break; 224 225 case TB_BLOCK: 226 if (head && TREE_CODE (head) == BIND_EXPR) 227 TB_SET_HEAD (TREE_OPERAND (head, 2)); 228 else 229 TB_WF; 230 break; 231 232 case TB_SUBBLOCKS: 233 if (head && TREE_CODE (head) == BLOCK) 234 TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); 235 else 236 TB_WF; 237 break; 238 239 case TB_SUPERCONTEXT: 240 if (head && TREE_CODE (head) == BLOCK) 241 TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); 242 else 243 TB_WF; 244 break; 245 246 case TB_VARS: 247 if (head && TREE_CODE (head) == BLOCK) 248 TB_SET_HEAD (BLOCK_VARS (head)); 249 else if (head && TREE_CODE (head) == BIND_EXPR) 250 TB_SET_HEAD (TREE_OPERAND (head, 0)); 251 else 252 TB_WF; 253 break; 254 255 case TB_REFERENCE_TO_THIS: 256 if (head && TYPE_P (head)) 257 TB_SET_HEAD (TYPE_REFERENCE_TO (head)); 258 else 259 TB_WF; 260 break; 261 262 case TB_POINTER_TO_THIS: 263 if (head && TYPE_P (head)) 264 TB_SET_HEAD (TYPE_POINTER_TO (head)); 265 else 266 TB_WF; 267 break; 268 269 case TB_BASETYPE: 270 if (head && TREE_CODE (head) == OFFSET_TYPE) 271 TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); 272 else 273 TB_WF; 274 break; 275 276 case TB_ARG_TYPES: 277 if (head && (TREE_CODE (head) == FUNCTION_TYPE 278 || TREE_CODE (head) == METHOD_TYPE)) 279 TB_SET_HEAD (TYPE_ARG_TYPES (head)); 280 else 281 TB_WF; 282 break; 283 284 case TB_METHOD_BASE_TYPE: 285 if (head && (TREE_CODE (head) == FUNCTION_TYPE 286 || TREE_CODE (head) == METHOD_TYPE) 287 && TYPE_METHOD_BASETYPE (head)) 288 TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); 289 else 290 TB_WF; 291 break; 292 293 case TB_FIELDS: 294 if (head && (TREE_CODE (head) == RECORD_TYPE 295 || TREE_CODE (head) == UNION_TYPE 296 || TREE_CODE (head) == QUAL_UNION_TYPE)) 297 TB_SET_HEAD (TYPE_FIELDS (head)); 298 else 299 TB_WF; 300 break; 301 302 case TB_DOMAIN: 303 if (head && TREE_CODE (head) == ARRAY_TYPE) 304 TB_SET_HEAD (TYPE_DOMAIN (head)); 305 else 306 TB_WF; 307 break; 308 309 case TB_VALUES: 310 if (head && TREE_CODE (head) == ENUMERAL_TYPE) 311 TB_SET_HEAD (TYPE_VALUES (head)); 312 else 313 TB_WF; 314 break; 315 316 case TB_ARG_TYPE: 317 if (head && TREE_CODE (head) == PARM_DECL) 318 TB_SET_HEAD (DECL_ARG_TYPE (head)); 319 else 320 TB_WF; 321 break; 322 323 case TB_INITIAL: 324 if (head && DECL_P (head)) 325 TB_SET_HEAD (DECL_INITIAL (head)); 326 else 327 TB_WF; 328 break; 329 330 case TB_RESULT: 331 if (head && DECL_P (head)) 332 TB_SET_HEAD (DECL_RESULT_FLD (head)); 333 else 334 TB_WF; 335 break; 336 337 case TB_ARGUMENTS: 338 if (head && DECL_P (head)) 339 TB_SET_HEAD (DECL_ARGUMENTS (head)); 340 else 341 TB_WF; 342 break; 343 344 case TB_ABSTRACT_ORIGIN: 345 if (head && DECL_P (head)) 346 TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); 347 else if (head && TREE_CODE (head) == BLOCK) 348 TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); 349 else 350 TB_WF; 351 break; 352 353 case TB_ATTRIBUTES: 354 if (head && DECL_P (head)) 355 TB_SET_HEAD (DECL_ATTRIBUTES (head)); 356 else if (head && TYPE_P (head)) 357 TB_SET_HEAD (TYPE_ATTRIBUTES (head)); 358 else 359 TB_WF; 360 break; 361 362 case TB_CONTEXT: 363 if (head && DECL_P (head)) 364 TB_SET_HEAD (DECL_CONTEXT (head)); 365 else if (head && TYPE_P (head) 366 && TYPE_CONTEXT (head)) 367 TB_SET_HEAD (TYPE_CONTEXT (head)); 368 else 369 TB_WF; 370 break; 371 372 case TB_OFFSET: 373 if (head && TREE_CODE (head) == FIELD_DECL) 374 TB_SET_HEAD (DECL_FIELD_OFFSET (head)); 375 else 376 TB_WF; 377 break; 378 379 case TB_BIT_OFFSET: 380 if (head && TREE_CODE (head) == FIELD_DECL) 381 TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); 382 else 383 TB_WF; 384 break; 385 386 case TB_UNIT_SIZE: 387 if (head && DECL_P (head)) 388 TB_SET_HEAD (DECL_SIZE_UNIT (head)); 389 else if (head && TYPE_P (head)) 390 TB_SET_HEAD (TYPE_SIZE_UNIT (head)); 391 else 392 TB_WF; 393 break; 394 395 case TB_SIZE: 396 if (head && DECL_P (head)) 397 TB_SET_HEAD (DECL_SIZE (head)); 398 else if (head && TYPE_P (head)) 399 TB_SET_HEAD (TYPE_SIZE (head)); 400 else 401 TB_WF; 402 break; 403 404 case TB_TYPE: 405 if (head && TREE_TYPE (head)) 406 TB_SET_HEAD (TREE_TYPE (head)); 407 else 408 TB_WF; 409 break; 410 411 case TB_DECL_SAVED_TREE: 412 if (head && TREE_CODE (head) == FUNCTION_DECL 413 && DECL_SAVED_TREE (head)) 414 TB_SET_HEAD (DECL_SAVED_TREE (head)); 415 else 416 TB_WF; 417 break; 418 419 case TB_BODY: 420 if (head && TREE_CODE (head) == BIND_EXPR) 421 TB_SET_HEAD (TREE_OPERAND (head, 1)); 422 else 423 TB_WF; 424 break; 425 426 case TB_CHILD_0: 427 if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) 428 TB_SET_HEAD (TREE_OPERAND (head, 0)); 429 else 430 TB_WF; 431 break; 432 433 case TB_CHILD_1: 434 if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) 435 TB_SET_HEAD (TREE_OPERAND (head, 1)); 436 else 437 TB_WF; 438 break; 439 440 case TB_CHILD_2: 441 if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) 442 TB_SET_HEAD (TREE_OPERAND (head, 2)); 443 else 444 TB_WF; 445 break; 446 447 case TB_CHILD_3: 448 if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) 449 TB_SET_HEAD (TREE_OPERAND (head, 3)); 450 else 451 TB_WF; 452 break; 453 454 case TB_PRINT: 455 if (head) 456 debug_tree (head); 457 else 458 TB_WF; 459 break; 460 461 case TB_PRETTY_PRINT: 462 if (head) 463 { 464 print_generic_stmt (TB_OUT_FILE, head, 0); 465 fprintf (TB_OUT_FILE, "\n"); 466 } 467 else 468 TB_WF; 469 break; 470 471 case TB_SEARCH_NAME: 472 473 break; 474 475 case TB_SEARCH_CODE: 476 { 477 enum tree_code code; 478 char *arg_text; 479 480 arg_text = strchr (input, ' '); 481 if (arg_text == NULL) 482 { 483 fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); 484 break; 485 } 486 code = TB_get_tree_code (arg_text + 1); 487 488 /* Search in the subtree a node with the given code. */ 489 { 490 tree res; 491 492 res = walk_tree (&head, find_node_with_code, &code, NULL); 493 if (res == NULL_TREE) 494 { 495 fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); 496 } 497 else 498 { 499 fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); 500 TB_SET_HEAD (res); 501 } 502 } 503 break; 504 } 505 506 #define TB_MOVE_HEAD(FCT) do { \ 507 if (head) \ 508 { \ 509 tree t; \ 510 t = FCT (head); \ 511 if (t) \ 512 TB_SET_HEAD (t); \ 513 else \ 514 TB_WF; \ 515 } \ 516 else \ 517 TB_WF; \ 518 } while (0) 519 520 case TB_FIRST: 521 TB_MOVE_HEAD (TB_first_in_bind); 522 break; 523 524 case TB_LAST: 525 TB_MOVE_HEAD (TB_last_in_bind); 526 break; 527 528 case TB_UP: 529 TB_MOVE_HEAD (TB_up_expr); 530 break; 531 532 case TB_PREV: 533 TB_MOVE_HEAD (TB_prev_expr); 534 break; 535 536 case TB_NEXT: 537 TB_MOVE_HEAD (TB_next_expr); 538 break; 539 540 case TB_HPREV: 541 /* This command is a little bit special, since it deals with history 542 stack. For this reason it should keep the "head = ..." statement 543 and not use TB_MOVE_HEAD. */ 544 if (head) 545 { 546 tree t; 547 t = TB_history_prev (); 548 if (t) 549 { 550 head = t; 551 if (TB_verbose) 552 { 553 print_generic_expr (TB_OUT_FILE, head, 0); 554 fprintf (TB_OUT_FILE, "\n"); 555 } 556 } 557 else 558 TB_WF; 559 } 560 else 561 TB_WF; 562 break; 563 564 case TB_CHAIN: 565 /* Don't go further if it's the last node in this chain. */ 566 if (head && TREE_CODE (head) == BLOCK) 567 TB_SET_HEAD (BLOCK_CHAIN (head)); 568 else if (head && TREE_CHAIN (head)) 569 TB_SET_HEAD (TREE_CHAIN (head)); 570 else 571 TB_WF; 572 break; 573 574 case TB_FUN: 575 /* Go up to the current function declaration. */ 576 TB_SET_HEAD (current_function_decl); 577 fprintf (TB_OUT_FILE, "Current function declaration.\n"); 578 break; 579 580 case TB_HELP: 581 /* Display a help message. */ 582 { 583 int i; 584 fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); 585 for (i = 0; i < TB_UNUSED_COMMAND; i++) 586 { 587 fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); 588 } 589 } 590 break; 591 592 case TB_VERBOSE: 593 if (TB_verbose == 0) 594 { 595 TB_verbose = 1; 596 fprintf (TB_OUT_FILE, "Verbose on.\n"); 597 } 598 else 599 { 600 TB_verbose = 0; 601 fprintf (TB_OUT_FILE, "Verbose off.\n"); 602 } 603 break; 604 605 case TB_EXIT: 606 case TB_QUIT: 607 /* Just exit from this function. */ 608 goto ret; 609 610 default: 611 TB_NIY; 612 } 613 } 614 615 ret:; 616 htab_delete (TB_up_ht); 617 return; 618 } 619 620 621 /* Search the first node in this BIND_EXPR. */ 622 623 static tree 624 TB_first_in_bind (tree node) 625 { 626 tree t; 627 628 if (node == NULL_TREE) 629 return NULL_TREE; 630 631 while ((t = TB_prev_expr (node))) 632 node = t; 633 634 return node; 635 } 636 637 /* Search the last node in this BIND_EXPR. */ 638 639 static tree 640 TB_last_in_bind (tree node) 641 { 642 tree t; 643 644 if (node == NULL_TREE) 645 return NULL_TREE; 646 647 while ((t = TB_next_expr (node))) 648 node = t; 649 650 return node; 651 } 652 653 /* Search the parent expression for this node. */ 654 655 static tree 656 TB_up_expr (tree node) 657 { 658 tree res; 659 if (node == NULL_TREE) 660 return NULL_TREE; 661 662 res = (tree) htab_find (TB_up_ht, node); 663 return res; 664 } 665 666 /* Search the previous expression in this BIND_EXPR. */ 667 668 static tree 669 TB_prev_expr (tree node) 670 { 671 node = TB_current_chain_node (node); 672 673 if (node == NULL_TREE) 674 return NULL_TREE; 675 676 node = TB_up_expr (node); 677 if (node && TREE_CODE (node) == COMPOUND_EXPR) 678 return node; 679 else 680 return NULL_TREE; 681 } 682 683 /* Search the next expression in this BIND_EXPR. */ 684 685 static tree 686 TB_next_expr (tree node) 687 { 688 node = TB_current_chain_node (node); 689 690 if (node == NULL_TREE) 691 return NULL_TREE; 692 693 node = TREE_OPERAND (node, 1); 694 return node; 695 } 696 697 static tree 698 TB_current_chain_node (tree node) 699 { 700 if (node == NULL_TREE) 701 return NULL_TREE; 702 703 if (TREE_CODE (node) == COMPOUND_EXPR) 704 return node; 705 706 node = TB_up_expr (node); 707 if (node) 708 { 709 if (TREE_CODE (node) == COMPOUND_EXPR) 710 return node; 711 712 node = TB_up_expr (node); 713 if (TREE_CODE (node) == COMPOUND_EXPR) 714 return node; 715 } 716 717 return NULL_TREE; 718 } 719 720 /* For each node store in its children nodes that the current node is their 721 parent. This function is used by walk_tree. */ 722 723 static tree 724 store_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 725 void *data ATTRIBUTE_UNUSED) 726 { 727 tree node; 728 void **slot; 729 730 node = *tp; 731 732 /* 'node' is the parent of 'TREE_OPERAND (node, *)'. */ 733 if (EXPR_P (node)) 734 { 735 int n = TREE_OPERAND_LENGTH (node); 736 int i; 737 for (i = 0; i < n; i++) 738 { 739 tree op = TREE_OPERAND (node, i); 740 slot = htab_find_slot (TB_up_ht, op, INSERT); 741 *slot = (void *) node; 742 } 743 } 744 745 /* Never stop walk_tree. */ 746 return NULL_TREE; 747 } 748 749 /* Function used in TB_up_ht. */ 750 751 static int 752 TB_parent_eq (const void *p1, const void *p2) 753 { 754 const_tree const node = (const_tree)p2; 755 const_tree const parent = (const_tree) p1; 756 757 if (p1 == NULL || p2 == NULL) 758 return 0; 759 760 if (EXPR_P (parent)) 761 { 762 int n = TREE_OPERAND_LENGTH (parent); 763 int i; 764 for (i = 0; i < n; i++) 765 if (node == TREE_OPERAND (parent, i)) 766 return 1; 767 } 768 return 0; 769 } 770 771 /* Update information about upper expressions in the hash table. */ 772 773 static void 774 TB_update_up (tree node) 775 { 776 while (node) 777 { 778 walk_tree (&node, store_child_info, NULL, NULL); 779 780 /* Walk function's body. */ 781 if (TREE_CODE (node) == FUNCTION_DECL) 782 if (DECL_SAVED_TREE (node)) 783 walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL); 784 785 /* Walk rest of the chain. */ 786 node = TREE_CHAIN (node); 787 } 788 fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n"); 789 } 790 791 /* Parse the input string for determining the command the user asked for. */ 792 793 static TB_CODE 794 TB_get_command (char *input) 795 { 796 unsigned int mn, size_tok; 797 int comp; 798 char *space; 799 800 space = strchr (input, ' '); 801 if (space != NULL) 802 size_tok = strlen (input) - strlen (space); 803 else 804 size_tok = strlen (input) - 1; 805 806 for (mn = 0; mn < TB_UNUSED_COMMAND; mn++) 807 { 808 if (size_tok != TB_COMMAND_LEN (mn)) 809 continue; 810 811 comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn)); 812 if (comp == 0) 813 /* Here we just determined the command. If this command takes 814 an argument, then the argument is determined later. */ 815 return TB_COMMAND_CODE (mn); 816 } 817 818 /* Not a valid command. */ 819 return TB_UNUSED_COMMAND; 820 } 821 822 /* Parse the input string for determining the tree code. */ 823 824 static enum tree_code 825 TB_get_tree_code (char *input) 826 { 827 unsigned int mn, size_tok; 828 int comp; 829 char *space; 830 831 space = strchr (input, ' '); 832 if (space != NULL) 833 size_tok = strlen (input) - strlen (space); 834 else 835 size_tok = strlen (input) - 1; 836 837 for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++) 838 { 839 if (size_tok != TB_TREE_CODE_LEN (mn)) 840 continue; 841 842 comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn)); 843 if (comp == 0) 844 { 845 fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn)); 846 return TB_TREE_CODE (mn); 847 } 848 } 849 850 /* This isn't a valid code. */ 851 return LAST_AND_UNUSED_TREE_CODE; 852 } 853 854 /* Find a node with a given code. This function is used as an argument to 855 walk_tree. */ 856 857 static tree 858 find_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 859 void *data) 860 { 861 enum tree_code *code; 862 code = (enum tree_code *) data; 863 if (*code == TREE_CODE (*tp)) 864 return *tp; 865 866 return NULL_TREE; 867 } 868 869 /* Returns a pointer to the last visited node. */ 870 871 static tree 872 TB_history_prev (void) 873 { 874 if (!VEC_empty (tree, TB_history_stack)) 875 { 876 tree last = VEC_last (tree, TB_history_stack); 877 VEC_pop (tree, TB_history_stack); 878 return last; 879 } 880 return NULL_TREE; 881 } 882 883 /* Read up to (and including) a '\n' from STREAM into *LINEPTR 884 (and null-terminate it). *LINEPTR is a pointer returned from malloc 885 (or NULL), pointing to *N characters of space. It is realloc'd as 886 necessary. Returns the number of characters read (not including the 887 null terminator), or -1 on error or EOF. 888 This function comes from sed (and is supposed to be a portable version 889 of getline). */ 890 891 static long 892 TB_getline (char **lineptr, long *n, FILE *stream) 893 { 894 char *line, *p; 895 long size, copy; 896 897 if (lineptr == NULL || n == NULL) 898 { 899 errno = EINVAL; 900 return -1; 901 } 902 903 if (ferror (stream)) 904 return -1; 905 906 /* Make sure we have a line buffer to start with. */ 907 if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */ 908 { 909 #ifndef MAX_CANON 910 #define MAX_CANON 256 911 #endif 912 line = (char *) xrealloc (*lineptr, MAX_CANON); 913 if (line == NULL) 914 return -1; 915 *lineptr = line; 916 *n = MAX_CANON; 917 } 918 919 line = *lineptr; 920 size = *n; 921 922 copy = size; 923 p = line; 924 925 while (1) 926 { 927 long len; 928 929 while (--copy > 0) 930 { 931 register int c = getc (stream); 932 if (c == EOF) 933 goto lose; 934 else if ((*p++ = c) == '\n') 935 goto win; 936 } 937 938 /* Need to enlarge the line buffer. */ 939 len = p - line; 940 size *= 2; 941 line = (char *) xrealloc (line, size); 942 if (line == NULL) 943 goto lose; 944 *lineptr = line; 945 *n = size; 946 p = line + len; 947 copy = size - len; 948 } 949 950 lose: 951 if (p == *lineptr) 952 return -1; 953 954 /* Return a partial line since we got an error in the middle. */ 955 win: 956 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) 957 if (p - 2 >= *lineptr && p[-2] == '\r') 958 p[-2] = p[-1], --p; 959 #endif 960 *p = '\0'; 961 return p - *lineptr; 962 } 963