OSDN Git Service

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