1169689Skan/* Tree browser. 2169689Skan Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. 3169689Skan Contributed by Sebastian Pop <s.pop@laposte.net> 4169689Skan 5169689SkanThis file is part of GCC. 6169689Skan 7169689SkanGCC is free software; you can redistribute it and/or modify it under 8169689Skanthe terms of the GNU General Public License as published by the Free 9169689SkanSoftware Foundation; either version 2, or (at your option) any later 10169689Skanversion. 11169689Skan 12169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY 13169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or 14169689SkanFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15169689Skanfor more details. 16169689Skan 17169689SkanYou should have received a copy of the GNU General Public License 18169689Skanalong with GCC; see the file COPYING. If not, write to the Free 19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169689Skan02110-1301, USA. */ 21169689Skan 22169689Skan#include "config.h" 23169689Skan#include "system.h" 24169689Skan#include "coretypes.h" 25169689Skan#include "tm.h" 26169689Skan#include "tree.h" 27169689Skan#include "tree-inline.h" 28169689Skan#include "diagnostic.h" 29169689Skan#include "hashtab.h" 30169689Skan 31169689Skan 32169689Skan#define TB_OUT_FILE stdout 33169689Skan#define TB_IN_FILE stdin 34169689Skan#define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n") 35169689Skan#define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n") 36169689Skan 37169689Skan 38169689Skan/* Structures for handling Tree Browser's commands. */ 39169689Skan#define DEFTBCODE(COMMAND, STRING, HELP) COMMAND, 40169689Skanenum TB_Comm_code { 41169689Skan#include "tree-browser.def" 42169689Skan TB_UNUSED_COMMAND 43169689Skan}; 44169689Skan#undef DEFTBCODE 45169689Skantypedef enum TB_Comm_code TB_CODE; 46169689Skan 47169689Skanstruct tb_command { 48169689Skan const char *help_msg; 49169689Skan const char *comm_text; 50169689Skan size_t comm_len; 51169689Skan TB_CODE comm_code; 52169689Skan}; 53169689Skan 54169689Skan#define DEFTBCODE(code, str, help) { help, str, sizeof(str) - 1, code }, 55169689Skanstatic const struct tb_command tb_commands[] = 56169689Skan{ 57169689Skan#include "tree-browser.def" 58169689Skan}; 59169689Skan#undef DEFTBCODE 60169689Skan 61169689Skan#define TB_COMMAND_LEN(N) (tb_commands[N].comm_len) 62169689Skan#define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text) 63169689Skan#define TB_COMMAND_CODE(N) (tb_commands[N].comm_code) 64169689Skan#define TB_COMMAND_HELP(N) (tb_commands[N].help_msg) 65169689Skan 66169689Skan 67169689Skan/* Next structure is for parsing TREE_CODEs. */ 68169689Skanstruct tb_tree_code { 69169689Skan enum tree_code code; 70169689Skan const char *code_string; 71169689Skan size_t code_string_len; 72169689Skan}; 73169689Skan 74169689Skan#define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 }, 75169689Skanstatic const struct tb_tree_code tb_tree_codes[] = 76169689Skan{ 77169689Skan#include "tree.def" 78169689Skan}; 79169689Skan#undef DEFTREECODE 80169689Skan 81169689Skan#define TB_TREE_CODE(N) (tb_tree_codes[N].code) 82169689Skan#define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string) 83169689Skan#define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len) 84169689Skan 85169689Skan 86169689Skan/* Function declarations. */ 87169689Skan 88169689Skanstatic long TB_getline (char **, long *, FILE *); 89169689Skanstatic TB_CODE TB_get_command (char *); 90169689Skanstatic enum tree_code TB_get_tree_code (char *); 91169689Skanstatic tree find_node_with_code (tree *, int *, void *); 92169689Skanstatic tree store_child_info (tree *, int *, void *); 93169689Skanstatic void TB_update_up (tree); 94169689Skanstatic tree TB_current_chain_node (tree); 95169689Skanstatic tree TB_prev_expr (tree); 96169689Skanstatic tree TB_next_expr (tree); 97169689Skanstatic tree TB_up_expr (tree); 98169689Skanstatic tree TB_first_in_bind (tree); 99169689Skanstatic tree TB_last_in_bind (tree); 100169689Skanstatic int TB_parent_eq (const void *, const void *); 101169689Skanstatic tree TB_history_prev (void); 102169689Skan 103169689Skan/* FIXME: To be declared in a .h file. */ 104169689Skanvoid browse_tree (tree); 105169689Skan 106169689Skan/* Static variables. */ 107169689Skanstatic htab_t TB_up_ht; 108169689Skanstatic tree TB_history_stack = NULL_TREE; 109169689Skanstatic int TB_verbose = 1; 110169689Skan 111169689Skan 112169689Skan/* Entry point in the Tree Browser. */ 113169689Skan 114169689Skanvoid 115169689Skanbrowse_tree (tree begin) 116169689Skan{ 117169689Skan tree head; 118169689Skan TB_CODE tbc = TB_UNUSED_COMMAND; 119169689Skan ssize_t rd; 120169689Skan char *input = NULL; 121169689Skan long input_size = 0; 122169689Skan 123169689Skan fprintf (TB_OUT_FILE, "\nTree Browser\n"); 124169689Skan 125169689Skan#define TB_SET_HEAD(N) do { \ 126169689Skan TB_history_stack = tree_cons (NULL_TREE, (N), TB_history_stack); \ 127169689Skan head = N; \ 128169689Skan if (TB_verbose) \ 129169689Skan if (head) \ 130169689Skan { \ 131169689Skan print_generic_expr (TB_OUT_FILE, head, 0); \ 132169689Skan fprintf (TB_OUT_FILE, "\n"); \ 133169689Skan } \ 134169689Skan} while (0) 135169689Skan 136169689Skan TB_SET_HEAD (begin); 137169689Skan 138169689Skan /* Store in a hashtable information about previous and upper statements. */ 139169689Skan { 140169689Skan TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL); 141169689Skan TB_update_up (head); 142169689Skan } 143169689Skan 144169689Skan while (24) 145169689Skan { 146169689Skan fprintf (TB_OUT_FILE, "TB> "); 147169689Skan rd = TB_getline (&input, &input_size, TB_IN_FILE); 148169689Skan 149169689Skan if (rd == -1) 150169689Skan /* EOF. */ 151169689Skan goto ret; 152169689Skan 153169689Skan if (rd != 1) 154169689Skan /* Get a new command. Otherwise the user just pressed enter, and thus 155169689Skan she expects the last command to be reexecuted. */ 156169689Skan tbc = TB_get_command (input); 157169689Skan 158169689Skan switch (tbc) 159169689Skan { 160169689Skan case TB_UPDATE_UP: 161169689Skan TB_update_up (head); 162169689Skan break; 163169689Skan 164169689Skan case TB_MAX: 165169689Skan if (head && (INTEGRAL_TYPE_P (head) 166169689Skan || TREE_CODE (head) == REAL_TYPE)) 167169689Skan TB_SET_HEAD (TYPE_MAX_VALUE (head)); 168169689Skan else 169169689Skan TB_WF; 170169689Skan break; 171169689Skan 172169689Skan case TB_MIN: 173169689Skan if (head && (INTEGRAL_TYPE_P (head) 174169689Skan || TREE_CODE (head) == REAL_TYPE)) 175169689Skan TB_SET_HEAD (TYPE_MIN_VALUE (head)); 176169689Skan else 177169689Skan TB_WF; 178169689Skan break; 179169689Skan 180169689Skan case TB_ELT: 181169689Skan if (head && TREE_CODE (head) == TREE_VEC) 182169689Skan { 183169689Skan /* This command takes another argument: the element number: 184169689Skan for example "elt 1". */ 185169689Skan TB_NIY; 186169689Skan } 187169689Skan else if (head && TREE_CODE (head) == VECTOR_CST) 188169689Skan { 189169689Skan /* This command takes another argument: the element number: 190169689Skan for example "elt 1". */ 191169689Skan TB_NIY; 192169689Skan } 193169689Skan else 194169689Skan TB_WF; 195169689Skan break; 196169689Skan 197169689Skan case TB_VALUE: 198169689Skan if (head && TREE_CODE (head) == TREE_LIST) 199169689Skan TB_SET_HEAD (TREE_VALUE (head)); 200169689Skan else 201169689Skan TB_WF; 202169689Skan break; 203169689Skan 204169689Skan case TB_PURPOSE: 205169689Skan if (head && TREE_CODE (head) == TREE_LIST) 206169689Skan TB_SET_HEAD (TREE_PURPOSE (head)); 207169689Skan else 208169689Skan TB_WF; 209169689Skan break; 210169689Skan 211169689Skan case TB_IMAG: 212169689Skan if (head && TREE_CODE (head) == COMPLEX_CST) 213169689Skan TB_SET_HEAD (TREE_IMAGPART (head)); 214169689Skan else 215169689Skan TB_WF; 216169689Skan break; 217169689Skan 218169689Skan case TB_REAL: 219169689Skan if (head && TREE_CODE (head) == COMPLEX_CST) 220169689Skan TB_SET_HEAD (TREE_REALPART (head)); 221169689Skan else 222169689Skan TB_WF; 223169689Skan break; 224169689Skan 225169689Skan case TB_BLOCK: 226169689Skan if (head && TREE_CODE (head) == BIND_EXPR) 227169689Skan TB_SET_HEAD (TREE_OPERAND (head, 2)); 228169689Skan else 229169689Skan TB_WF; 230169689Skan break; 231169689Skan 232169689Skan case TB_SUBBLOCKS: 233169689Skan if (head && TREE_CODE (head) == BLOCK) 234169689Skan TB_SET_HEAD (BLOCK_SUBBLOCKS (head)); 235169689Skan else 236169689Skan TB_WF; 237169689Skan break; 238169689Skan 239169689Skan case TB_SUPERCONTEXT: 240169689Skan if (head && TREE_CODE (head) == BLOCK) 241169689Skan TB_SET_HEAD (BLOCK_SUPERCONTEXT (head)); 242169689Skan else 243169689Skan TB_WF; 244169689Skan break; 245169689Skan 246169689Skan case TB_VARS: 247169689Skan if (head && TREE_CODE (head) == BLOCK) 248169689Skan TB_SET_HEAD (BLOCK_VARS (head)); 249169689Skan else if (head && TREE_CODE (head) == BIND_EXPR) 250169689Skan TB_SET_HEAD (TREE_OPERAND (head, 0)); 251169689Skan else 252169689Skan TB_WF; 253169689Skan break; 254169689Skan 255169689Skan case TB_REFERENCE_TO_THIS: 256169689Skan if (head && TYPE_P (head)) 257169689Skan TB_SET_HEAD (TYPE_REFERENCE_TO (head)); 258169689Skan else 259169689Skan TB_WF; 260169689Skan break; 261169689Skan 262169689Skan case TB_POINTER_TO_THIS: 263169689Skan if (head && TYPE_P (head)) 264169689Skan TB_SET_HEAD (TYPE_POINTER_TO (head)); 265169689Skan else 266169689Skan TB_WF; 267169689Skan break; 268169689Skan 269169689Skan case TB_BASETYPE: 270169689Skan if (head && TREE_CODE (head) == OFFSET_TYPE) 271169689Skan TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head)); 272169689Skan else 273169689Skan TB_WF; 274169689Skan break; 275169689Skan 276169689Skan case TB_ARG_TYPES: 277169689Skan if (head && (TREE_CODE (head) == FUNCTION_TYPE 278169689Skan || TREE_CODE (head) == METHOD_TYPE)) 279169689Skan TB_SET_HEAD (TYPE_ARG_TYPES (head)); 280169689Skan else 281169689Skan TB_WF; 282169689Skan break; 283169689Skan 284169689Skan case TB_METHOD_BASE_TYPE: 285169689Skan if (head && (TREE_CODE (head) == FUNCTION_TYPE 286169689Skan || TREE_CODE (head) == METHOD_TYPE) 287169689Skan && TYPE_METHOD_BASETYPE (head)) 288169689Skan TB_SET_HEAD (TYPE_METHOD_BASETYPE (head)); 289169689Skan else 290169689Skan TB_WF; 291169689Skan break; 292169689Skan 293169689Skan case TB_FIELDS: 294169689Skan if (head && (TREE_CODE (head) == RECORD_TYPE 295169689Skan || TREE_CODE (head) == UNION_TYPE 296169689Skan || TREE_CODE (head) == QUAL_UNION_TYPE)) 297169689Skan TB_SET_HEAD (TYPE_FIELDS (head)); 298169689Skan else 299169689Skan TB_WF; 300169689Skan break; 301169689Skan 302169689Skan case TB_DOMAIN: 303169689Skan if (head && TREE_CODE (head) == ARRAY_TYPE) 304169689Skan TB_SET_HEAD (TYPE_DOMAIN (head)); 305169689Skan else 306169689Skan TB_WF; 307169689Skan break; 308169689Skan 309169689Skan case TB_VALUES: 310169689Skan if (head && TREE_CODE (head) == ENUMERAL_TYPE) 311169689Skan TB_SET_HEAD (TYPE_VALUES (head)); 312169689Skan else 313169689Skan TB_WF; 314169689Skan break; 315169689Skan 316169689Skan case TB_ARG_TYPE: 317169689Skan if (head && TREE_CODE (head) == PARM_DECL) 318169689Skan TB_SET_HEAD (DECL_ARG_TYPE (head)); 319169689Skan else 320169689Skan TB_WF; 321169689Skan break; 322169689Skan 323169689Skan case TB_INITIAL: 324169689Skan if (head && DECL_P (head)) 325169689Skan TB_SET_HEAD (DECL_INITIAL (head)); 326169689Skan else 327169689Skan TB_WF; 328169689Skan break; 329169689Skan 330169689Skan case TB_RESULT: 331169689Skan if (head && DECL_P (head)) 332169689Skan TB_SET_HEAD (DECL_RESULT_FLD (head)); 333169689Skan else 334169689Skan TB_WF; 335169689Skan break; 336169689Skan 337169689Skan case TB_ARGUMENTS: 338169689Skan if (head && DECL_P (head)) 339169689Skan TB_SET_HEAD (DECL_ARGUMENTS (head)); 340169689Skan else 341169689Skan TB_WF; 342169689Skan break; 343169689Skan 344169689Skan case TB_ABSTRACT_ORIGIN: 345169689Skan if (head && DECL_P (head)) 346169689Skan TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head)); 347169689Skan else if (head && TREE_CODE (head) == BLOCK) 348169689Skan TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head)); 349169689Skan else 350169689Skan TB_WF; 351169689Skan break; 352169689Skan 353169689Skan case TB_ATTRIBUTES: 354169689Skan if (head && DECL_P (head)) 355169689Skan TB_SET_HEAD (DECL_ATTRIBUTES (head)); 356169689Skan else if (head && TYPE_P (head)) 357169689Skan TB_SET_HEAD (TYPE_ATTRIBUTES (head)); 358169689Skan else 359169689Skan TB_WF; 360169689Skan break; 361169689Skan 362169689Skan case TB_CONTEXT: 363169689Skan if (head && DECL_P (head)) 364169689Skan TB_SET_HEAD (DECL_CONTEXT (head)); 365169689Skan else if (head && TYPE_P (head) 366169689Skan && TYPE_CONTEXT (head)) 367169689Skan TB_SET_HEAD (TYPE_CONTEXT (head)); 368169689Skan else 369169689Skan TB_WF; 370169689Skan break; 371169689Skan 372169689Skan case TB_OFFSET: 373169689Skan if (head && TREE_CODE (head) == FIELD_DECL) 374169689Skan TB_SET_HEAD (DECL_FIELD_OFFSET (head)); 375169689Skan else 376169689Skan TB_WF; 377169689Skan break; 378169689Skan 379169689Skan case TB_BIT_OFFSET: 380169689Skan if (head && TREE_CODE (head) == FIELD_DECL) 381169689Skan TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head)); 382169689Skan else 383169689Skan TB_WF; 384169689Skan break; 385169689Skan 386169689Skan case TB_UNIT_SIZE: 387169689Skan if (head && DECL_P (head)) 388169689Skan TB_SET_HEAD (DECL_SIZE_UNIT (head)); 389169689Skan else if (head && TYPE_P (head)) 390169689Skan TB_SET_HEAD (TYPE_SIZE_UNIT (head)); 391169689Skan else 392169689Skan TB_WF; 393169689Skan break; 394169689Skan 395169689Skan case TB_SIZE: 396169689Skan if (head && DECL_P (head)) 397169689Skan TB_SET_HEAD (DECL_SIZE (head)); 398169689Skan else if (head && TYPE_P (head)) 399169689Skan TB_SET_HEAD (TYPE_SIZE (head)); 400169689Skan else 401169689Skan TB_WF; 402169689Skan break; 403169689Skan 404169689Skan case TB_TYPE: 405169689Skan if (head && TREE_TYPE (head)) 406169689Skan TB_SET_HEAD (TREE_TYPE (head)); 407169689Skan else 408169689Skan TB_WF; 409169689Skan break; 410169689Skan 411169689Skan case TB_DECL_SAVED_TREE: 412169689Skan if (head && TREE_CODE (head) == FUNCTION_DECL 413169689Skan && DECL_SAVED_TREE (head)) 414169689Skan TB_SET_HEAD (DECL_SAVED_TREE (head)); 415169689Skan else 416169689Skan TB_WF; 417169689Skan break; 418169689Skan 419169689Skan case TB_BODY: 420169689Skan if (head && TREE_CODE (head) == BIND_EXPR) 421169689Skan TB_SET_HEAD (TREE_OPERAND (head, 1)); 422169689Skan else 423169689Skan TB_WF; 424169689Skan break; 425169689Skan 426169689Skan case TB_CHILD_0: 427169689Skan if (head && EXPR_P (head) && TREE_OPERAND (head, 0)) 428169689Skan TB_SET_HEAD (TREE_OPERAND (head, 0)); 429169689Skan else 430169689Skan TB_WF; 431169689Skan break; 432169689Skan 433169689Skan case TB_CHILD_1: 434169689Skan if (head && EXPR_P (head) && TREE_OPERAND (head, 1)) 435169689Skan TB_SET_HEAD (TREE_OPERAND (head, 1)); 436169689Skan else 437169689Skan TB_WF; 438169689Skan break; 439169689Skan 440169689Skan case TB_CHILD_2: 441169689Skan if (head && EXPR_P (head) && TREE_OPERAND (head, 2)) 442169689Skan TB_SET_HEAD (TREE_OPERAND (head, 2)); 443169689Skan else 444169689Skan TB_WF; 445169689Skan break; 446169689Skan 447169689Skan case TB_CHILD_3: 448169689Skan if (head && EXPR_P (head) && TREE_OPERAND (head, 3)) 449169689Skan TB_SET_HEAD (TREE_OPERAND (head, 3)); 450169689Skan else 451169689Skan TB_WF; 452169689Skan break; 453169689Skan 454169689Skan case TB_PRINT: 455169689Skan if (head) 456169689Skan debug_tree (head); 457169689Skan else 458169689Skan TB_WF; 459169689Skan break; 460169689Skan 461169689Skan case TB_PRETTY_PRINT: 462169689Skan if (head) 463169689Skan { 464169689Skan print_generic_stmt (TB_OUT_FILE, head, 0); 465169689Skan fprintf (TB_OUT_FILE, "\n"); 466169689Skan } 467169689Skan else 468169689Skan TB_WF; 469169689Skan break; 470169689Skan 471169689Skan case TB_SEARCH_NAME: 472169689Skan 473169689Skan break; 474169689Skan 475169689Skan case TB_SEARCH_CODE: 476169689Skan { 477169689Skan enum tree_code code; 478169689Skan char *arg_text; 479169689Skan 480169689Skan arg_text = strchr (input, ' '); 481169689Skan if (arg_text == NULL) 482169689Skan { 483169689Skan fprintf (TB_OUT_FILE, "First argument is missing. This isn't a valid search command. \n"); 484169689Skan break; 485169689Skan } 486169689Skan code = TB_get_tree_code (arg_text + 1); 487169689Skan 488169689Skan /* Search in the subtree a node with the given code. */ 489169689Skan { 490169689Skan tree res; 491169689Skan 492169689Skan res = walk_tree (&head, find_node_with_code, &code, NULL); 493169689Skan if (res == NULL_TREE) 494169689Skan { 495169689Skan fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n"); 496169689Skan } 497169689Skan else 498169689Skan { 499169689Skan fprintf (TB_OUT_FILE, "Achoo! I got this node in the tree.\n"); 500169689Skan TB_SET_HEAD (res); 501169689Skan } 502169689Skan } 503169689Skan break; 504169689Skan } 505169689Skan 506169689Skan#define TB_MOVE_HEAD(FCT) do { \ 507169689Skan if (head) \ 508169689Skan { \ 509169689Skan tree t; \ 510169689Skan t = FCT (head); \ 511169689Skan if (t) \ 512169689Skan TB_SET_HEAD (t); \ 513169689Skan else \ 514169689Skan TB_WF; \ 515169689Skan } \ 516169689Skan else \ 517169689Skan TB_WF; \ 518169689Skan} while (0) 519169689Skan 520169689Skan case TB_FIRST: 521169689Skan TB_MOVE_HEAD (TB_first_in_bind); 522169689Skan break; 523169689Skan 524169689Skan case TB_LAST: 525169689Skan TB_MOVE_HEAD (TB_last_in_bind); 526169689Skan break; 527169689Skan 528169689Skan case TB_UP: 529169689Skan TB_MOVE_HEAD (TB_up_expr); 530169689Skan break; 531169689Skan 532169689Skan case TB_PREV: 533169689Skan TB_MOVE_HEAD (TB_prev_expr); 534169689Skan break; 535169689Skan 536169689Skan case TB_NEXT: 537169689Skan TB_MOVE_HEAD (TB_next_expr); 538169689Skan break; 539169689Skan 540169689Skan case TB_HPREV: 541169689Skan /* This command is a little bit special, since it deals with history 542169689Skan stack. For this reason it should keep the "head = ..." statement 543169689Skan and not use TB_MOVE_HEAD. */ 544169689Skan if (head) 545169689Skan { 546169689Skan tree t; 547169689Skan t = TB_history_prev (); 548169689Skan if (t) 549169689Skan { 550169689Skan head = t; 551169689Skan if (TB_verbose) 552169689Skan { 553169689Skan print_generic_expr (TB_OUT_FILE, head, 0); 554169689Skan fprintf (TB_OUT_FILE, "\n"); 555169689Skan } 556169689Skan } 557169689Skan else 558169689Skan TB_WF; 559169689Skan } 560169689Skan else 561169689Skan TB_WF; 562169689Skan break; 563169689Skan 564169689Skan case TB_CHAIN: 565169689Skan /* Don't go further if it's the last node in this chain. */ 566169689Skan if (head && TREE_CODE (head) == BLOCK) 567169689Skan TB_SET_HEAD (BLOCK_CHAIN (head)); 568169689Skan else if (head && TREE_CHAIN (head)) 569169689Skan TB_SET_HEAD (TREE_CHAIN (head)); 570169689Skan else 571169689Skan TB_WF; 572169689Skan break; 573169689Skan 574169689Skan case TB_FUN: 575169689Skan /* Go up to the current function declaration. */ 576169689Skan TB_SET_HEAD (current_function_decl); 577169689Skan fprintf (TB_OUT_FILE, "Current function declaration.\n"); 578169689Skan break; 579169689Skan 580169689Skan case TB_HELP: 581169689Skan /* Display a help message. */ 582169689Skan { 583169689Skan int i; 584169689Skan fprintf (TB_OUT_FILE, "Possible commands are:\n\n"); 585169689Skan for (i = 0; i < TB_UNUSED_COMMAND; i++) 586169689Skan { 587169689Skan fprintf (TB_OUT_FILE, "%20s - %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i)); 588169689Skan } 589169689Skan } 590169689Skan break; 591169689Skan 592169689Skan case TB_VERBOSE: 593169689Skan if (TB_verbose == 0) 594169689Skan { 595169689Skan TB_verbose = 1; 596169689Skan fprintf (TB_OUT_FILE, "Verbose on.\n"); 597169689Skan } 598169689Skan else 599169689Skan { 600169689Skan TB_verbose = 0; 601169689Skan fprintf (TB_OUT_FILE, "Verbose off.\n"); 602169689Skan } 603169689Skan break; 604169689Skan 605169689Skan case TB_EXIT: 606169689Skan case TB_QUIT: 607169689Skan /* Just exit from this function. */ 608169689Skan goto ret; 609169689Skan 610169689Skan default: 611169689Skan TB_NIY; 612169689Skan } 613169689Skan } 614169689Skan 615169689Skan ret:; 616169689Skan htab_delete (TB_up_ht); 617169689Skan return; 618169689Skan} 619169689Skan 620169689Skan 621169689Skan/* Search the first node in this BIND_EXPR. */ 622169689Skan 623169689Skanstatic tree 624169689SkanTB_first_in_bind (tree node) 625169689Skan{ 626169689Skan tree t; 627169689Skan 628169689Skan if (node == NULL_TREE) 629169689Skan return NULL_TREE; 630169689Skan 631169689Skan while ((t = TB_prev_expr (node))) 632169689Skan node = t; 633169689Skan 634169689Skan return node; 635169689Skan} 636169689Skan 637169689Skan/* Search the last node in this BIND_EXPR. */ 638169689Skan 639169689Skanstatic tree 640169689SkanTB_last_in_bind (tree node) 641169689Skan{ 642169689Skan tree t; 643169689Skan 644169689Skan if (node == NULL_TREE) 645169689Skan return NULL_TREE; 646169689Skan 647169689Skan while ((t = TB_next_expr (node))) 648169689Skan node = t; 649169689Skan 650169689Skan return node; 651169689Skan} 652169689Skan 653169689Skan/* Search the parent expression for this node. */ 654169689Skan 655169689Skanstatic tree 656169689SkanTB_up_expr (tree node) 657169689Skan{ 658169689Skan tree res; 659169689Skan if (node == NULL_TREE) 660169689Skan return NULL_TREE; 661169689Skan 662169689Skan res = (tree) htab_find (TB_up_ht, node); 663169689Skan return res; 664169689Skan} 665169689Skan 666169689Skan/* Search the previous expression in this BIND_EXPR. */ 667169689Skan 668169689Skanstatic tree 669169689SkanTB_prev_expr (tree node) 670169689Skan{ 671169689Skan node = TB_current_chain_node (node); 672169689Skan 673169689Skan if (node == NULL_TREE) 674169689Skan return NULL_TREE; 675169689Skan 676169689Skan node = TB_up_expr (node); 677169689Skan if (node && TREE_CODE (node) == COMPOUND_EXPR) 678169689Skan return node; 679169689Skan else 680169689Skan return NULL_TREE; 681169689Skan} 682169689Skan 683169689Skan/* Search the next expression in this BIND_EXPR. */ 684169689Skan 685169689Skanstatic tree 686169689SkanTB_next_expr (tree node) 687169689Skan{ 688169689Skan node = TB_current_chain_node (node); 689169689Skan 690169689Skan if (node == NULL_TREE) 691169689Skan return NULL_TREE; 692169689Skan 693169689Skan node = TREE_OPERAND (node, 1); 694169689Skan return node; 695169689Skan} 696169689Skan 697169689Skanstatic tree 698169689SkanTB_current_chain_node (tree node) 699169689Skan{ 700169689Skan if (node == NULL_TREE) 701169689Skan return NULL_TREE; 702169689Skan 703169689Skan if (TREE_CODE (node) == COMPOUND_EXPR) 704169689Skan return node; 705169689Skan 706169689Skan node = TB_up_expr (node); 707169689Skan if (node) 708169689Skan { 709169689Skan if (TREE_CODE (node) == COMPOUND_EXPR) 710169689Skan return node; 711169689Skan 712169689Skan node = TB_up_expr (node); 713169689Skan if (TREE_CODE (node) == COMPOUND_EXPR) 714169689Skan return node; 715169689Skan } 716169689Skan 717169689Skan return NULL_TREE; 718169689Skan} 719169689Skan 720169689Skan/* For each node store in its children nodes that the current node is their 721169689Skan parent. This function is used by walk_tree. */ 722169689Skan 723169689Skanstatic tree 724169689Skanstore_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 725169689Skan void *data ATTRIBUTE_UNUSED) 726169689Skan{ 727169689Skan tree node; 728169689Skan void **slot; 729169689Skan 730169689Skan node = *tp; 731169689Skan 732169689Skan /* 'node' is the parent of 'TREE_OPERAND (node, *)'. */ 733169689Skan if (EXPRESSION_CLASS_P (node)) 734169689Skan { 735169689Skan 736169689Skan#define STORE_CHILD(N) do { \ 737169689Skan tree op = TREE_OPERAND (node, N); \ 738169689Skan slot = htab_find_slot (TB_up_ht, op, INSERT); \ 739169689Skan *slot = (void *) node; \ 740169689Skan} while (0) 741169689Skan 742169689Skan switch (TREE_CODE_LENGTH (TREE_CODE (node))) 743169689Skan { 744169689Skan case 4: 745169689Skan STORE_CHILD (0); 746169689Skan STORE_CHILD (1); 747169689Skan STORE_CHILD (2); 748169689Skan STORE_CHILD (3); 749169689Skan break; 750169689Skan 751169689Skan case 3: 752169689Skan STORE_CHILD (0); 753169689Skan STORE_CHILD (1); 754169689Skan STORE_CHILD (2); 755169689Skan break; 756169689Skan 757169689Skan case 2: 758169689Skan STORE_CHILD (0); 759169689Skan STORE_CHILD (1); 760169689Skan break; 761169689Skan 762169689Skan case 1: 763169689Skan STORE_CHILD (0); 764169689Skan break; 765169689Skan 766169689Skan case 0: 767169689Skan default: 768169689Skan /* No children: nothing to do. */ 769169689Skan break; 770169689Skan } 771169689Skan#undef STORE_CHILD 772169689Skan } 773169689Skan 774169689Skan /* Never stop walk_tree. */ 775169689Skan return NULL_TREE; 776169689Skan} 777169689Skan 778169689Skan/* Function used in TB_up_ht. */ 779169689Skan 780169689Skanstatic int 781169689SkanTB_parent_eq (const void *p1, const void *p2) 782169689Skan{ 783169689Skan tree node, parent; 784169689Skan node = (tree) p2; 785169689Skan parent = (tree) p1; 786169689Skan 787169689Skan if (p1 == NULL || p2 == NULL) 788169689Skan return 0; 789169689Skan 790169689Skan if (EXPRESSION_CLASS_P (parent)) 791169689Skan { 792169689Skan 793169689Skan#define TEST_CHILD(N) do { \ 794169689Skan if (node == TREE_OPERAND (parent, N)) \ 795169689Skan return 1; \ 796169689Skan} while (0) 797169689Skan 798169689Skan switch (TREE_CODE_LENGTH (TREE_CODE (parent))) 799169689Skan { 800169689Skan case 4: 801169689Skan TEST_CHILD (0); 802169689Skan TEST_CHILD (1); 803169689Skan TEST_CHILD (2); 804169689Skan TEST_CHILD (3); 805169689Skan break; 806169689Skan 807169689Skan case 3: 808169689Skan TEST_CHILD (0); 809169689Skan TEST_CHILD (1); 810169689Skan TEST_CHILD (2); 811169689Skan break; 812169689Skan 813169689Skan case 2: 814169689Skan TEST_CHILD (0); 815169689Skan TEST_CHILD (1); 816169689Skan break; 817169689Skan 818169689Skan case 1: 819169689Skan TEST_CHILD (0); 820169689Skan break; 821169689Skan 822169689Skan case 0: 823169689Skan default: 824169689Skan /* No children: nothing to do. */ 825169689Skan break; 826169689Skan } 827169689Skan#undef TEST_CHILD 828169689Skan } 829169689Skan 830169689Skan return 0; 831169689Skan} 832169689Skan 833169689Skan/* Update information about upper expressions in the hash table. */ 834169689Skan 835169689Skanstatic void 836169689SkanTB_update_up (tree node) 837169689Skan{ 838169689Skan while (node) 839169689Skan { 840169689Skan walk_tree (&node, store_child_info, NULL, NULL); 841169689Skan 842169689Skan /* Walk function's body. */ 843169689Skan if (TREE_CODE (node) == FUNCTION_DECL) 844169689Skan if (DECL_SAVED_TREE (node)) 845169689Skan walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL); 846169689Skan 847169689Skan /* Walk rest of the chain. */ 848169689Skan node = TREE_CHAIN (node); 849169689Skan } 850169689Skan fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n"); 851169689Skan} 852169689Skan 853169689Skan/* Parse the input string for determining the command the user asked for. */ 854169689Skan 855169689Skanstatic TB_CODE 856169689SkanTB_get_command (char *input) 857169689Skan{ 858169689Skan unsigned int mn, size_tok; 859169689Skan int comp; 860169689Skan char *space; 861169689Skan 862169689Skan space = strchr (input, ' '); 863169689Skan if (space != NULL) 864169689Skan size_tok = strlen (input) - strlen (space); 865169689Skan else 866169689Skan size_tok = strlen (input) - 1; 867169689Skan 868169689Skan for (mn = 0; mn < TB_UNUSED_COMMAND; mn++) 869169689Skan { 870169689Skan if (size_tok != TB_COMMAND_LEN (mn)) 871169689Skan continue; 872169689Skan 873169689Skan comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn)); 874169689Skan if (comp == 0) 875169689Skan /* Here we just determined the command. If this command takes 876169689Skan an argument, then the argument is determined later. */ 877169689Skan return TB_COMMAND_CODE (mn); 878169689Skan } 879169689Skan 880169689Skan /* Not a valid command. */ 881169689Skan return TB_UNUSED_COMMAND; 882169689Skan} 883169689Skan 884169689Skan/* Parse the input string for determining the tree code. */ 885169689Skan 886169689Skanstatic enum tree_code 887169689SkanTB_get_tree_code (char *input) 888169689Skan{ 889169689Skan unsigned int mn, size_tok; 890169689Skan int comp; 891169689Skan char *space; 892169689Skan 893169689Skan space = strchr (input, ' '); 894169689Skan if (space != NULL) 895169689Skan size_tok = strlen (input) - strlen (space); 896169689Skan else 897169689Skan size_tok = strlen (input) - 1; 898169689Skan 899169689Skan for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++) 900169689Skan { 901169689Skan if (size_tok != TB_TREE_CODE_LEN (mn)) 902169689Skan continue; 903169689Skan 904169689Skan comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn)); 905169689Skan if (comp == 0) 906169689Skan { 907169689Skan fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn)); 908169689Skan return TB_TREE_CODE (mn); 909169689Skan } 910169689Skan } 911169689Skan 912169689Skan /* This isn't a valid code. */ 913169689Skan return LAST_AND_UNUSED_TREE_CODE; 914169689Skan} 915169689Skan 916169689Skan/* Find a node with a given code. This function is used as an argument to 917169689Skan walk_tree. */ 918169689Skan 919169689Skanstatic tree 920169689Skanfind_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, 921169689Skan void *data) 922169689Skan{ 923169689Skan enum tree_code *code; 924169689Skan code = (enum tree_code *) data; 925169689Skan if (*code == TREE_CODE (*tp)) 926169689Skan return *tp; 927169689Skan 928169689Skan return NULL_TREE; 929169689Skan} 930169689Skan 931169689Skan/* Returns a pointer to the last visited node. */ 932169689Skan 933169689Skanstatic tree 934169689SkanTB_history_prev (void) 935169689Skan{ 936169689Skan if (TB_history_stack) 937169689Skan { 938169689Skan TB_history_stack = TREE_CHAIN (TB_history_stack); 939169689Skan if (TB_history_stack) 940169689Skan return TREE_VALUE (TB_history_stack); 941169689Skan } 942169689Skan return NULL_TREE; 943169689Skan} 944169689Skan 945169689Skan/* Read up to (and including) a '\n' from STREAM into *LINEPTR 946169689Skan (and null-terminate it). *LINEPTR is a pointer returned from malloc 947169689Skan (or NULL), pointing to *N characters of space. It is realloc'd as 948169689Skan necessary. Returns the number of characters read (not including the 949169689Skan null terminator), or -1 on error or EOF. 950169689Skan This function comes from sed (and is supposed to be a portable version 951169689Skan of getline). */ 952169689Skan 953169689Skanstatic long 954169689SkanTB_getline (char **lineptr, long *n, FILE *stream) 955169689Skan{ 956169689Skan char *line, *p; 957169689Skan long size, copy; 958169689Skan 959169689Skan if (lineptr == NULL || n == NULL) 960169689Skan { 961169689Skan errno = EINVAL; 962169689Skan return -1; 963169689Skan } 964169689Skan 965169689Skan if (ferror (stream)) 966169689Skan return -1; 967169689Skan 968169689Skan /* Make sure we have a line buffer to start with. */ 969169689Skan if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */ 970169689Skan { 971169689Skan#ifndef MAX_CANON 972169689Skan#define MAX_CANON 256 973169689Skan#endif 974169689Skan line = (char *) xrealloc (*lineptr, MAX_CANON); 975169689Skan if (line == NULL) 976169689Skan return -1; 977169689Skan *lineptr = line; 978169689Skan *n = MAX_CANON; 979169689Skan } 980169689Skan 981169689Skan line = *lineptr; 982169689Skan size = *n; 983169689Skan 984169689Skan copy = size; 985169689Skan p = line; 986169689Skan 987169689Skan while (1) 988169689Skan { 989169689Skan long len; 990169689Skan 991169689Skan while (--copy > 0) 992169689Skan { 993169689Skan register int c = getc (stream); 994169689Skan if (c == EOF) 995169689Skan goto lose; 996169689Skan else if ((*p++ = c) == '\n') 997169689Skan goto win; 998169689Skan } 999169689Skan 1000169689Skan /* Need to enlarge the line buffer. */ 1001169689Skan len = p - line; 1002169689Skan size *= 2; 1003169689Skan line = (char *) xrealloc (line, size); 1004169689Skan if (line == NULL) 1005169689Skan goto lose; 1006169689Skan *lineptr = line; 1007169689Skan *n = size; 1008169689Skan p = line + len; 1009169689Skan copy = size - len; 1010169689Skan } 1011169689Skan 1012169689Skan lose: 1013169689Skan if (p == *lineptr) 1014169689Skan return -1; 1015169689Skan 1016169689Skan /* Return a partial line since we got an error in the middle. */ 1017169689Skan win: 1018169689Skan#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS) 1019169689Skan if (p - 2 >= *lineptr && p[-2] == '\r') 1020169689Skan p[-2] = p[-1], --p; 1021169689Skan#endif 1022169689Skan *p = '\0'; 1023169689Skan return p - *lineptr; 1024169689Skan} 1025