OSDN Git Service

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