OSDN Git Service

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