xref: /dragonfly/contrib/gcc-4.7/gcc/tree-browser.c (revision 04febcfb30580676d3e95f58a16c5137ee478b32)
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;
VEC(tree,gc)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
TB_first_in_bind(tree node)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
TB_last_in_bind(tree node)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
TB_up_expr(tree node)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
TB_prev_expr(tree node)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
TB_next_expr(tree node)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
TB_current_chain_node(tree node)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
store_child_info(tree * tp,int * walk_subtrees ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED)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
TB_parent_eq(const void * p1,const void * p2)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
TB_update_up(tree node)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
TB_get_command(char * input)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
TB_get_tree_code(char * input)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
find_node_with_code(tree * tp,int * walk_subtrees ATTRIBUTE_UNUSED,void * data)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
TB_history_prev(void)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
TB_getline(char ** lineptr,long * n,FILE * stream)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 }
963