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