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