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