OSDN Git Service

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