OSDN Git Service

2005-07-07 Feng Wang <fengwang@nudt.edu.cn>
[pf3gnuchains/gcc-fork.git] / gcc / tree-browser.c
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
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_AS_WRITTEN:
317           if (head && TREE_CODE (head) == PARM_DECL)
318             TB_SET_HEAD (DECL_ARG_TYPE_AS_WRITTEN (head));
319           else
320             TB_WF;
321           break;
322
323         case TB_ARG_TYPE:
324           if (head && TREE_CODE (head) == PARM_DECL)
325             TB_SET_HEAD (DECL_ARG_TYPE (head));
326           else
327             TB_WF;
328           break;
329
330         case TB_INITIAL:
331           if (head && DECL_P (head))
332             TB_SET_HEAD (DECL_INITIAL (head));
333           else
334             TB_WF;
335           break;
336
337         case TB_RESULT:
338           if (head && DECL_P (head))
339             TB_SET_HEAD (DECL_RESULT_FLD (head));
340           else
341             TB_WF;
342           break;
343
344         case TB_ARGUMENTS:
345           if (head && DECL_P (head))
346             TB_SET_HEAD (DECL_ARGUMENTS (head));
347           else
348             TB_WF;
349           break;
350
351         case TB_ABSTRACT_ORIGIN:
352           if (head && DECL_P (head))
353             TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head));
354           else if (head && TREE_CODE (head) == BLOCK)
355             TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head));
356           else
357             TB_WF;
358           break;
359
360         case TB_ATTRIBUTES:
361           if (head && DECL_P (head))
362             TB_SET_HEAD (DECL_ATTRIBUTES (head));
363           else if (head && TYPE_P (head))
364             TB_SET_HEAD (TYPE_ATTRIBUTES (head));
365           else
366             TB_WF;
367           break;
368
369         case TB_CONTEXT:
370           if (head && DECL_P (head))
371             TB_SET_HEAD (DECL_CONTEXT (head));
372           else if (head && TYPE_P (head)
373                    && TYPE_CONTEXT (head))
374             TB_SET_HEAD (TYPE_CONTEXT (head));
375           else
376             TB_WF;
377           break;
378
379         case TB_OFFSET:
380           if (head && TREE_CODE (head) == FIELD_DECL)
381             TB_SET_HEAD (DECL_FIELD_OFFSET (head));
382           else
383             TB_WF;
384           break;
385
386         case TB_BIT_OFFSET:
387           if (head && TREE_CODE (head) == FIELD_DECL)
388             TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head));
389           else
390             TB_WF;
391           break;
392
393         case TB_UNIT_SIZE:
394           if (head && DECL_P (head))
395             TB_SET_HEAD (DECL_SIZE_UNIT (head));
396           else if (head && TYPE_P (head))
397             TB_SET_HEAD (TYPE_SIZE_UNIT (head));
398           else
399             TB_WF;
400           break;
401
402         case TB_SIZE:
403           if (head && DECL_P (head))
404             TB_SET_HEAD (DECL_SIZE (head));
405           else if (head && TYPE_P (head))
406             TB_SET_HEAD (TYPE_SIZE (head));
407           else
408             TB_WF;
409           break;
410
411         case TB_TYPE:
412           if (head && TREE_TYPE (head))
413             TB_SET_HEAD (TREE_TYPE (head));
414           else
415             TB_WF;
416           break;
417
418         case TB_DECL_SAVED_TREE:
419           if (head && TREE_CODE (head) == FUNCTION_DECL
420               && DECL_SAVED_TREE (head))
421             TB_SET_HEAD (DECL_SAVED_TREE (head));
422           else
423             TB_WF;
424           break;
425
426         case TB_BODY:
427           if (head && TREE_CODE (head) == BIND_EXPR)
428             TB_SET_HEAD (TREE_OPERAND (head, 1));
429           else
430             TB_WF;
431           break;
432
433         case TB_CHILD_0:
434           if (head && EXPR_P (head) && TREE_OPERAND (head, 0))
435             TB_SET_HEAD (TREE_OPERAND (head, 0));
436           else
437             TB_WF;
438           break;
439
440         case TB_CHILD_1:
441           if (head && EXPR_P (head) && TREE_OPERAND (head, 1))
442             TB_SET_HEAD (TREE_OPERAND (head, 1));
443           else
444             TB_WF;
445           break;
446
447         case TB_CHILD_2:
448           if (head && EXPR_P (head) && TREE_OPERAND (head, 2))
449             TB_SET_HEAD (TREE_OPERAND (head, 2));
450           else
451             TB_WF;
452           break;
453
454         case TB_CHILD_3:
455           if (head && EXPR_P (head) && TREE_OPERAND (head, 3))
456             TB_SET_HEAD (TREE_OPERAND (head, 3));
457           else
458             TB_WF;
459           break;
460
461         case TB_PRINT:
462           if (head)
463             debug_tree (head);
464           else
465             TB_WF;
466           break;
467
468         case TB_PRETTY_PRINT:
469           if (head)
470             {
471               print_generic_stmt (TB_OUT_FILE, head, 0);
472               fprintf (TB_OUT_FILE, "\n");
473             }
474           else
475             TB_WF;
476           break;
477
478         case TB_SEARCH_NAME:
479
480           break;
481
482         case TB_SEARCH_CODE:
483           {
484             enum tree_code code;
485             char *arg_text;
486
487             arg_text = strchr (input, ' ');
488             if (arg_text == NULL)
489               {
490                 fprintf (TB_OUT_FILE, "First argument is missing.  This isn't a valid search command.  \n");
491                 break;
492               }
493             code = TB_get_tree_code (arg_text + 1);
494
495             /* Search in the subtree a node with the given code.  */
496             {
497               tree res;
498
499               res = walk_tree (&head, find_node_with_code, &code, NULL);
500               if (res == NULL_TREE)
501                 {
502                   fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n");
503                 }
504               else
505                 {
506                   fprintf (TB_OUT_FILE, "Achoo!  I got this node in the tree.\n");
507                   TB_SET_HEAD (res);
508                 }
509             }
510             break;
511           }
512
513 #define TB_MOVE_HEAD(FCT) do {       \
514   if (head)                          \
515     {                                \
516       tree t;                        \
517       t = FCT (head);                \
518       if (t)                         \
519         TB_SET_HEAD (t);             \
520       else                           \
521         TB_WF;                       \
522     }                                \
523   else                               \
524     TB_WF;                           \
525 } while (0)
526
527         case TB_FIRST:
528           TB_MOVE_HEAD (TB_first_in_bind);
529           break;
530
531         case TB_LAST:
532           TB_MOVE_HEAD (TB_last_in_bind);
533           break;
534
535         case TB_UP:
536           TB_MOVE_HEAD (TB_up_expr);
537           break;
538
539         case TB_PREV:
540           TB_MOVE_HEAD (TB_prev_expr);
541           break;
542
543         case TB_NEXT:
544           TB_MOVE_HEAD (TB_next_expr);
545           break;
546
547         case TB_HPREV:
548           /* This command is a little bit special, since it deals with history
549              stack.  For this reason it should keep the "head = ..." statement
550              and not use TB_MOVE_HEAD.  */
551           if (head)
552             {
553               tree t;
554               t = TB_history_prev ();
555               if (t)
556                 {
557                   head = t;
558                   if (TB_verbose)
559                     {
560                       print_generic_expr (TB_OUT_FILE, head, 0);
561                       fprintf (TB_OUT_FILE, "\n");
562                     }
563                 }
564               else
565                 TB_WF;
566             }
567           else
568             TB_WF;
569           break;
570
571         case TB_CHAIN:
572           /* Don't go further if it's the last node in this chain.  */
573           if (head && TREE_CODE (head) == BLOCK)
574             TB_SET_HEAD (BLOCK_CHAIN (head));
575           else if (head && TREE_CHAIN (head))
576             TB_SET_HEAD (TREE_CHAIN (head));
577           else
578             TB_WF;
579           break;
580
581         case TB_FUN:
582           /* Go up to the current function declaration.  */
583           TB_SET_HEAD (current_function_decl);
584           fprintf (TB_OUT_FILE, "Current function declaration.\n");
585           break;
586
587         case TB_HELP:
588           /* Display a help message.  */
589           {
590             int i;
591             fprintf (TB_OUT_FILE, "Possible commands are:\n\n");
592             for (i = 0; i < TB_UNUSED_COMMAND; i++)
593               {
594                 fprintf (TB_OUT_FILE, "%20s  -  %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i));
595               }
596           }
597           break;
598
599         case TB_VERBOSE:
600           if (TB_verbose == 0)
601             {
602               TB_verbose = 1;
603               fprintf (TB_OUT_FILE, "Verbose on.\n");
604             }
605           else
606             {
607               TB_verbose = 0;
608               fprintf (TB_OUT_FILE, "Verbose off.\n");
609             }
610           break;
611
612         case TB_EXIT:
613         case TB_QUIT:
614           /* Just exit from this function.  */
615           goto ret;
616
617         default:
618           TB_NIY;
619         }
620     }
621
622  ret:;
623   htab_delete (TB_up_ht);
624   return;
625 }
626
627
628 /* Search the first node in this BIND_EXPR.  */
629
630 static tree
631 TB_first_in_bind (tree node)
632 {
633   tree t;
634
635   if (node == NULL_TREE)
636     return NULL_TREE;
637
638   while ((t = TB_prev_expr (node)))
639     node = t;
640
641   return node;
642 }
643
644 /* Search the last node in this BIND_EXPR.  */
645
646 static tree
647 TB_last_in_bind (tree node)
648 {
649   tree t;
650
651   if (node == NULL_TREE)
652     return NULL_TREE;
653
654   while ((t = TB_next_expr (node)))
655     node = t;
656
657   return node;
658 }
659
660 /* Search the parent expression for this node.  */
661
662 static tree
663 TB_up_expr (tree node)
664 {
665   tree res;
666   if (node == NULL_TREE)
667     return NULL_TREE;
668
669   res = (tree) htab_find (TB_up_ht, node);
670   return res;
671 }
672
673 /* Search the previous expression in this BIND_EXPR.  */
674
675 static tree
676 TB_prev_expr (tree node)
677 {
678   node = TB_current_chain_node (node);
679
680   if (node == NULL_TREE)
681     return NULL_TREE;
682
683   node = TB_up_expr (node);
684   if (node && TREE_CODE (node) == COMPOUND_EXPR)
685     return node;
686   else
687     return NULL_TREE;
688 }
689
690 /* Search the next expression in this BIND_EXPR.  */
691
692 static tree
693 TB_next_expr (tree node)
694 {
695   node = TB_current_chain_node (node);
696
697   if (node == NULL_TREE)
698     return NULL_TREE;
699
700   node = TREE_OPERAND (node, 1);
701   return node;
702 }
703
704 static tree
705 TB_current_chain_node (tree node)
706 {
707   if (node == NULL_TREE)
708     return NULL_TREE;
709
710   if (TREE_CODE (node) == COMPOUND_EXPR)
711     return node;
712
713   node = TB_up_expr (node);
714   if (node)
715     {
716       if (TREE_CODE (node) == COMPOUND_EXPR)
717         return node;
718
719       node = TB_up_expr (node);
720       if (TREE_CODE (node) == COMPOUND_EXPR)
721         return node;
722     }
723
724   return NULL_TREE;
725 }
726
727 /* For each node store in its children nodes that the current node is their
728    parent.  This function is used by walk_tree.  */
729
730 static tree
731 store_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
732                   void *data ATTRIBUTE_UNUSED)
733 {
734   tree node;
735   void **slot;
736
737   node = *tp;
738
739   /* 'node' is the parent of 'TREE_OPERAND (node, *)'.  */
740   if (EXPRESSION_CLASS_P (node))
741     {
742
743 #define STORE_CHILD(N) do {                                                \
744   tree op = TREE_OPERAND (node, N);                                        \
745   slot = htab_find_slot (TB_up_ht, op, INSERT);                               \
746   *slot = (void *) node;                                                   \
747 } while (0)
748
749       switch (TREE_CODE_LENGTH (TREE_CODE (node)))
750         {
751         case 4:
752           STORE_CHILD (0);
753           STORE_CHILD (1);
754           STORE_CHILD (2);
755           STORE_CHILD (3);
756           break;
757
758         case 3:
759           STORE_CHILD (0);
760           STORE_CHILD (1);
761           STORE_CHILD (2);
762           break;
763
764         case 2:
765           STORE_CHILD (0);
766           STORE_CHILD (1);
767           break;
768
769         case 1:
770           STORE_CHILD (0);
771           break;
772
773         case 0:
774         default:
775           /* No children: nothing to do.  */
776           break;
777         }
778 #undef STORE_CHILD
779     }
780
781   /* Never stop walk_tree.  */
782   return NULL_TREE;
783 }
784
785 /* Function used in TB_up_ht.  */
786
787 static int
788 TB_parent_eq (const void *p1, const void *p2)
789 {
790   tree node, parent;
791   node = (tree) p2;
792   parent = (tree) p1;
793
794   if (p1 == NULL || p2 == NULL)
795     return 0;
796
797   if (EXPRESSION_CLASS_P (parent))
798     {
799
800 #define TEST_CHILD(N) do {               \
801   if (node == TREE_OPERAND (parent, N))  \
802     return 1;                            \
803 } while (0)
804
805     switch (TREE_CODE_LENGTH (TREE_CODE (parent)))
806       {
807       case 4:
808         TEST_CHILD (0);
809         TEST_CHILD (1);
810         TEST_CHILD (2);
811         TEST_CHILD (3);
812         break;
813
814       case 3:
815         TEST_CHILD (0);
816         TEST_CHILD (1);
817         TEST_CHILD (2);
818         break;
819
820       case 2:
821         TEST_CHILD (0);
822         TEST_CHILD (1);
823         break;
824
825       case 1:
826         TEST_CHILD (0);
827         break;
828
829       case 0:
830       default:
831         /* No children: nothing to do.  */
832         break;
833       }
834 #undef TEST_CHILD
835     }
836
837   return 0;
838 }
839
840 /* Update information about upper expressions in the hash table.  */
841
842 static void
843 TB_update_up (tree node)
844 {
845   while (node)
846     {
847       walk_tree (&node, store_child_info, NULL, NULL);
848
849       /* Walk function's body.  */
850       if (TREE_CODE (node) == FUNCTION_DECL)
851         if (DECL_SAVED_TREE (node))
852           walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL);
853
854       /* Walk rest of the chain.  */
855       node = TREE_CHAIN (node);
856     }
857   fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n");
858 }
859
860 /* Parse the input string for determining the command the user asked for.  */
861
862 static TB_CODE
863 TB_get_command (char *input)
864 {
865   unsigned int mn, size_tok;
866   int comp;
867   char *space;
868
869   space = strchr (input, ' ');
870   if (space != NULL)
871     size_tok = strlen (input) - strlen (space);
872   else
873     size_tok = strlen (input) - 1;
874
875   for (mn = 0; mn < TB_UNUSED_COMMAND; mn++)
876     {
877       if (size_tok != TB_COMMAND_LEN (mn))
878         continue;
879
880       comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn));
881       if (comp == 0)
882         /* Here we just determined the command.  If this command takes
883            an argument, then the argument is determined later.  */
884         return TB_COMMAND_CODE (mn);
885     }
886
887   /* Not a valid command.  */
888   return TB_UNUSED_COMMAND;
889 }
890
891 /* Parse the input string for determining the tree code.  */
892
893 static enum tree_code
894 TB_get_tree_code (char *input)
895 {
896   unsigned int mn, size_tok;
897   int comp;
898   char *space;
899
900   space = strchr (input, ' ');
901   if (space != NULL)
902     size_tok = strlen (input) - strlen (space);
903   else
904     size_tok = strlen (input) - 1;
905
906   for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++)
907     {
908       if (size_tok != TB_TREE_CODE_LEN (mn))
909         continue;
910
911       comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn));
912       if (comp == 0)
913         {
914           fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn));
915           return TB_TREE_CODE (mn);
916         }
917     }
918
919   /* This isn't a valid code.  */
920   return LAST_AND_UNUSED_TREE_CODE;
921 }
922
923 /* Find a node with a given code.  This function is used as an argument to
924    walk_tree.  */
925
926 static tree
927 find_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
928                      void *data)
929 {
930   enum tree_code *code;
931   code = (enum tree_code *) data;
932   if (*code == TREE_CODE (*tp))
933     return *tp;
934
935   return NULL_TREE;
936 }
937
938 /* Returns a pointer to the last visited node.  */
939
940 static tree
941 TB_history_prev (void)
942 {
943   if (TB_history_stack)
944     {
945       TB_history_stack = TREE_CHAIN (TB_history_stack);
946       if (TB_history_stack)
947         return TREE_VALUE (TB_history_stack);
948     }
949   return NULL_TREE;
950 }
951
952 /* Read up to (and including) a '\n' from STREAM into *LINEPTR
953    (and null-terminate it). *LINEPTR is a pointer returned from malloc
954    (or NULL), pointing to *N characters of space.  It is realloc'd as
955    necessary.  Returns the number of characters read (not including the
956    null terminator), or -1 on error or EOF.
957    This function comes from sed (and is supposed to be a portable version
958    of getline).  */
959
960 static long
961 TB_getline (char **lineptr, long *n, FILE *stream)
962 {
963   char *line, *p;
964   long size, copy;
965
966   if (lineptr == NULL || n == NULL)
967     {
968       errno = EINVAL;
969       return -1;
970     }
971
972   if (ferror (stream))
973     return -1;
974
975   /* Make sure we have a line buffer to start with.  */
976   if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars.  */
977     {
978 #ifndef MAX_CANON
979 #define MAX_CANON       256
980 #endif
981       line = (char *) xrealloc (*lineptr, MAX_CANON);
982       if (line == NULL)
983         return -1;
984       *lineptr = line;
985       *n = MAX_CANON;
986     }
987
988   line = *lineptr;
989   size = *n;
990
991   copy = size;
992   p = line;
993
994   while (1)
995     {
996       long len;
997
998       while (--copy > 0)
999         {
1000           register int c = getc (stream);
1001           if (c == EOF)
1002             goto lose;
1003           else if ((*p++ = c) == '\n')
1004             goto win;
1005         }
1006
1007       /* Need to enlarge the line buffer.  */
1008       len = p - line;
1009       size *= 2;
1010       line = (char *) xrealloc (line, size);
1011       if (line == NULL)
1012         goto lose;
1013       *lineptr = line;
1014       *n = size;
1015       p = line + len;
1016       copy = size - len;
1017     }
1018
1019  lose:
1020   if (p == *lineptr)
1021     return -1;
1022
1023   /* Return a partial line since we got an error in the middle.  */
1024  win:
1025 #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS)
1026   if (p - 2 >= *lineptr && p[-2] == '\r')
1027     p[-2] = p[-1], --p;
1028 #endif
1029   *p = '\0';
1030   return p - *lineptr;
1031 }