xref: /openbsd/gnu/gcc/gcc/tree-browser.c (revision 404b540a)
1 /* Tree browser.
2    Copyright (C) 2002, 2003, 2004 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 2, 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 COPYING.  If not, write to the Free
19 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-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,
40 enum TB_Comm_code {
41 #include "tree-browser.def"
42   TB_UNUSED_COMMAND
43 };
44 #undef DEFTBCODE
45 typedef enum TB_Comm_code TB_CODE;
46 
47 struct 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 },
55 static 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.  */
68 struct 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 },
75 static 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 
88 static long TB_getline (char **, long *, FILE *);
89 static TB_CODE TB_get_command (char *);
90 static enum tree_code TB_get_tree_code (char *);
91 static tree find_node_with_code (tree *, int *, void *);
92 static tree store_child_info (tree *, int *, void *);
93 static void TB_update_up (tree);
94 static tree TB_current_chain_node (tree);
95 static tree TB_prev_expr (tree);
96 static tree TB_next_expr (tree);
97 static tree TB_up_expr (tree);
98 static tree TB_first_in_bind (tree);
99 static tree TB_last_in_bind (tree);
100 static int  TB_parent_eq (const void *, const void *);
101 static tree TB_history_prev (void);
102 
103 /* FIXME: To be declared in a .h file.  */
104 void browse_tree (tree);
105 
106 /* Static variables.  */
107 static htab_t TB_up_ht;
108 static tree TB_history_stack = NULL_TREE;
109 static int TB_verbose = 1;
110 
111 
112 /* Entry point in the Tree Browser.  */
113 
114 void
browse_tree(tree begin)115 browse_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 
623 static tree
TB_first_in_bind(tree node)624 TB_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 
639 static tree
TB_last_in_bind(tree node)640 TB_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 
655 static tree
TB_up_expr(tree node)656 TB_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 
668 static tree
TB_prev_expr(tree node)669 TB_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 
685 static tree
TB_next_expr(tree node)686 TB_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 
697 static tree
TB_current_chain_node(tree node)698 TB_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 
723 static tree
store_child_info(tree * tp,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)724 store_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 
780 static int
TB_parent_eq(const void * p1,const void * p2)781 TB_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 
835 static void
TB_update_up(tree node)836 TB_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 
855 static TB_CODE
TB_get_command(char * input)856 TB_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 
886 static enum tree_code
TB_get_tree_code(char * input)887 TB_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 
919 static tree
find_node_with_code(tree * tp,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)920 find_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 
933 static tree
TB_history_prev(void)934 TB_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 
953 static long
TB_getline(char ** lineptr,long * n,FILE * stream)954 TB_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