OSDN Git Service

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