1/* Tree browser. 2 Copyright (C) 2002, 2003, 2004 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 2, 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 COPYING. If not, write to the Free 19Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 2002110-1301, USA. */ 21 22#include "config.h" 23#include "system.h" 24#include "coretypes.h" 25#include "tm.h" 26#include "tree.h" 27#include "tree-inline.h" 28#include "diagnostic.h" 29#include "hashtab.h" 30 31 32#define TB_OUT_FILE stdout 33#define TB_IN_FILE stdin 34#define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n") 35#define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n") 36 37 38/* Structures for handling Tree Browser's commands. */ 39#define DEFTBCODE(COMMAND, STRING, HELP) COMMAND, 40enum TB_Comm_code { 41#include "tree-browser.def" 42 TB_UNUSED_COMMAND 43}; 44#undef DEFTBCODE 45typedef enum TB_Comm_code TB_CODE; 46 47struct tb_command { 48 const char *help_msg; 49 const char *comm_text; 50 size_t comm_len; 51 TB_CODE comm_code; 52}; 53 54#define DEFTBCODE(code, str, help) { help, str, sizeof(str) - 1, code }, 55static const struct tb_command tb_commands[] = 56{ 57#include "tree-browser.def" 58}; 59#undef DEFTBCODE 60 61#define TB_COMMAND_LEN(N) (tb_commands[N].comm_len) 62#define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text) 63#define TB_COMMAND_CODE(N) (tb_commands[N].comm_code) 64#define TB_COMMAND_HELP(N) (tb_commands[N].help_msg) 65 66 67/* Next structure is for parsing TREE_CODEs. */ 68struct tb_tree_code { 69 enum tree_code code; 70 const char *code_string; 71 size_t code_string_len; 72}; 73 74#define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 }, 75static const struct tb_tree_code tb_tree_codes[] = 76{ 77#include "tree.def" 78}; 79#undef DEFTREECODE 80 81#define TB_TREE_CODE(N) (tb_tree_codes[N].code) 82#define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string) 83#define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len) 84 85 86/* Function declarations. */ 87 88static long TB_getline (char **, long *, FILE *); 89static TB_CODE TB_get_command (char *); 90static enum tree_code TB_get_tree_code (char *); 91static tree find_node_with_code (tree *, int *, void *); 92static tree store_child_info (tree *, int *, void *); 93static void TB_update_up (tree); 94static tree TB_current_chain_node (tree); 95static tree TB_prev_expr (tree); 96static tree TB_next_expr (tree); 97static tree TB_up_expr (tree); 98static tree TB_first_in_bind (tree); 99static tree TB_last_in_bind (tree); 100static int TB_parent_eq (const void *, const void *); 101static tree TB_history_prev (void); 102 103/* FIXME: To be declared in a .h file. */ 104void browse_tree (tree); 105 106/* Static variables. */ 107static htab_t TB_up_ht; 108static tree TB_history_stack = NULL_TREE; 109static int TB_verbose = 1; 110 111 112/* Entry point in the Tree Browser. */ 113 114void 115browse_tree (tree begin) 116{ 117 tree head; 118 TB_CODE tbc = TB_UNUSED_COMMAND; 119 ssize_t rd; 120 char *input = NULL; 121 long input_size = 0; 122 123 fprintf (TB_OUT_FILE, "\nTree Browser\n"); 124 125#define TB_SET_HEAD(N) do { \ 126 TB_history_stack = tree_cons (NULL_TREE, (N), TB_history_stack); \ 127 head = N; \ 128 if (TB_verbose) \ 129 if (head) \ 130 { \ 131 print_generic_expr (TB_OUT_FILE, head, 0); \ 132 fprintf (TB_OUT_FILE, "\n"); \ 133 } \ 134} while (0) 135 136 TB_SET_HEAD (begin); 137 138 /* Store in a hashtable information about previous and upper statements. */ 139 { 140 TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL); 141 TB_update_up (head); 142 } 143 144 while (24) 145 { 146 fprintf (TB_OUT_FILE, "TB> "); 147 rd = TB_getline (&input, &input_size, TB_IN_FILE); 148 149 if (rd == -1) 150 /* EOF. */ 151 goto ret; 152 153 if (rd != 1) 154 /* Get a new command. Otherwise the user just pressed enter, and thus 155 she expects the last command to be reexecuted. */ 156 tbc = TB_get_command (input); 157 158 switch (tbc) 159 { 160 case TB_UPDATE_UP: 161 TB_update_up (head); 162 break; 163 164 case TB_MAX: 165 if (head && (INTEGRAL_TYPE_P (head) 166 || TREE_CODE (head) == REAL_TYPE)) 167 TB_SET_HEAD (TYPE_MAX_VALUE (head)); 168 else 169 TB_WF; 170 break; 171 172 case TB_MIN: 173 if (head && (INTEGRAL_TYPE_P (head) 174 || TREE_CODE (head) == REAL_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 623static tree 624TB_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 639static tree 640TB_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 655static tree 656TB_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 668static tree 669TB_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 685static tree 686TB_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 697static tree 698TB_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 723static tree 724store_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 (EXPRESSION_CLASS_P (node)) 734 { 735 736#define STORE_CHILD(N) do { \ 737 tree op = TREE_OPERAND (node, N); \ 738 slot = htab_find_slot (TB_up_ht, op, INSERT); \ 739 *slot = (void *) node; \ 740} while (0) 741 742 switch (TREE_CODE_LENGTH (TREE_CODE (node))) 743 { 744 case 4: 745 STORE_CHILD (0); 746 STORE_CHILD (1); 747 STORE_CHILD (2); 748 STORE_CHILD (3); 749 break; 750 751 case 3: 752 STORE_CHILD (0); 753 STORE_CHILD (1); 754 STORE_CHILD (2); 755 break; 756 757 case 2: 758 STORE_CHILD (0); 759 STORE_CHILD (1); 760 break; 761 762 case 1: 763 STORE_CHILD (0); 764 break; 765 766 case 0: 767 default: 768 /* No children: nothing to do. */ 769 break; 770 } 771#undef STORE_CHILD 772 } 773 774 /* Never stop walk_tree. */ 775 return NULL_TREE; 776} 777 778/* Function used in TB_up_ht. */ 779 780static int 781TB_parent_eq (const void *p1, const void *p2) 782{ 783 tree node, parent; 784 node = (tree) p2; 785 parent = (tree) p1; 786 787 if (p1 == NULL || p2 == NULL) 788 return 0; 789 790 if (EXPRESSION_CLASS_P (parent)) 791 { 792 793#define TEST_CHILD(N) do { \ 794 if (node == TREE_OPERAND (parent, N)) \ 795 return 1; \ 796} while (0) 797 798 switch (TREE_CODE_LENGTH (TREE_CODE (parent))) 799 { 800 case 4: 801 TEST_CHILD (0); 802 TEST_CHILD (1); 803 TEST_CHILD (2); 804 TEST_CHILD (3); 805 break; 806 807 case 3: 808 TEST_CHILD (0); 809 TEST_CHILD (1); 810 TEST_CHILD (2); 811 break; 812 813 case 2: 814 TEST_CHILD (0); 815 TEST_CHILD (1); 816 break; 817 818 case 1: 819 TEST_CHILD (0); 820 break; 821 822 case 0: 823 default: 824 /* No children: nothing to do. */ 825 break; 826 } 827#undef TEST_CHILD 828 } 829 830 return 0; 831} 832 833/* Update information about upper expressions in the hash table. */ 834 835static void 836TB_update_up (tree node) 837{ 838 while (node) 839 { 840 walk_tree (&node, store_child_info, NULL, NULL); 841 842 /* Walk function's body. */ 843 if (TREE_CODE (node) == FUNCTION_DECL) 844 if (DECL_SAVED_TREE (node)) 845 walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL); 846 847 /* Walk rest of the chain. */ 848 node = TREE_CHAIN (node); 849 } 850 fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n"); 851} 852 853/* Parse the input string for determining the command the user asked for. */ 854 855static TB_CODE 856TB_get_command (char *input) 857{ 858 unsigned int mn, size_tok; 859 int comp; 860 char *space; 861 862 space = strchr (input, ' '); 863 if (space != NULL) 864 size_tok = strlen (input) - strlen (space); 865 else 866 size_tok = strlen (input) - 1; 867 868 for (mn = 0; mn < TB_UNUSED_COMMAND; mn++) 869 { 870 if (size_tok != TB_COMMAND_LEN (mn)) 871 continue; 872 873 comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn)); 874 if (comp == 0) 875 /* Here we just determined the command. If this command takes 876 an argument, then the argument is determined later. */ 877 return TB_COMMAND_CODE (mn); 878 } 879 880 /* Not a valid command. */ 881 return TB_UNUSED_COMMAND; 882} 883 884/* Parse the input string for determining the tree code. */ 885 886static enum tree_code 887TB_get_tree_code (char *input) 888{ 889 unsigned int mn, size_tok; 890 int comp; 891 char *space; 892 893 space = strchr (input, ' '); 894 if (space != NULL) 895 size_tok = strlen (input) - strlen (space); 896 else 897 size_tok = strlen (input) - 1; 898 899 for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++) 900 { 901 if (size_tok != TB_TREE_CODE_LEN (mn)) 902 continue; 903 904 comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn)); 905 if (comp == 0) 906 { 907 fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn)); 908 return TB_TREE_CODE (mn); 909 } 910 } 911 912 /* This isn't a valid code. */ 913 return LAST_AND_UNUSED_TREE_CODE; 914} 915 916/* Find a node with a given code. This function is used as an argument to 917 walk_tree. */ 918 919static tree 920find_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 921 void *data) 922{ 923 enum tree_code *code; 924 code = (enum tree_code *) data; 925 if (*code == TREE_CODE (*tp)) 926 return *tp; 927 928 return NULL_TREE; 929} 930 931/* Returns a pointer to the last visited node. */ 932 933static tree 934TB_history_prev (void) 935{ 936 if (TB_history_stack) 937 { 938 TB_history_stack = TREE_CHAIN (TB_history_stack); 939 if (TB_history_stack) 940 return TREE_VALUE (TB_history_stack); 941 } 942 return NULL_TREE; 943} 944 945/* Read up to (and including) a '\n' from STREAM into *LINEPTR 946 (and null-terminate it). *LINEPTR is a pointer returned from malloc 947 (or NULL), pointing to *N characters of space. It is realloc'd as 948 necessary. Returns the number of characters read (not including the 949 null terminator), or -1 on error or EOF. 950 This function comes from sed (and is supposed to be a portable version 951 of getline). */ 952 953static long 954TB_getline (char **lineptr, long *n, FILE *stream) 955{ 956 char *line, *p; 957 long size, copy; 958 959 if (lineptr == NULL || n == NULL) 960 { 961 errno = EINVAL; 962 return -1; 963 } 964 965 if (ferror (stream)) 966 return -1; 967 968 /* Make sure we have a line buffer to start with. */ 969 if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */ 970 { 971#ifndef MAX_CANON 972#define MAX_CANON 256 973#endif 974 line = (char *) xrealloc (*lineptr, MAX_CANON); 975 if (line == NULL) 976 return -1; 977 *lineptr = line; 978 *n = MAX_CANON; 979 } 980 981 line = *lineptr; 982 size = *n; 983 984 copy = size; 985 p = line; 986 987 while (1) 988 { 989 long len; 990 991 while (--copy > 0) 992 { 993 register int c = getc (stream); 994 if (c == EOF) 995 goto lose; 996 else if ((*p++ = c) == '\n') 997 goto win; 998 } 999 1000 /* Need to enlarge the line buffer. */ 1001 len = p - line; 1002 size *= 2; 1003 line = (char *) xrealloc (line, size); 1004 if (line == NULL) 1005 goto lose; 1006 *lineptr = line; 1007 *n = size; 1008 p = line + len; 1009 copy = size - len; 1010 } 1011 1012 lose: 1013 if (p == *lineptr) 1014 return -1; 1015 1016 /* Return a partial line since we got an error in the middle. */ 1017 win: 1018#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) 1019 if (p - 2 >= *lineptr && p[-2] == '\r') 1020 p[-2] = p[-1], --p; 1021#endif 1022 *p = '\0'; 1023 return p - *lineptr; 1024} 1025