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