OSDN Git Service

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