1169689Skan/* Tree browser.
2169689Skan   Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
3169689Skan   Contributed by Sebastian Pop <s.pop@laposte.net>
4169689Skan
5169689SkanThis file is part of GCC.
6169689Skan
7169689SkanGCC is free software; you can redistribute it and/or modify it under
8169689Skanthe terms of the GNU General Public License as published by the Free
9169689SkanSoftware Foundation; either version 2, or (at your option) any later
10169689Skanversion.
11169689Skan
12169689SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
13169689SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
14169689SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15169689Skanfor more details.
16169689Skan
17169689SkanYou should have received a copy of the GNU General Public License
18169689Skanalong with GCC; see the file COPYING.  If not, write to the Free
19169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20169689Skan02110-1301, USA.  */
21169689Skan
22169689Skan#include "config.h"
23169689Skan#include "system.h"
24169689Skan#include "coretypes.h"
25169689Skan#include "tm.h"
26169689Skan#include "tree.h"
27169689Skan#include "tree-inline.h"
28169689Skan#include "diagnostic.h"
29169689Skan#include "hashtab.h"
30169689Skan
31169689Skan
32169689Skan#define TB_OUT_FILE stdout
33169689Skan#define TB_IN_FILE stdin
34169689Skan#define TB_NIY fprintf (TB_OUT_FILE, "Sorry this command is not yet implemented.\n")
35169689Skan#define TB_WF fprintf (TB_OUT_FILE, "Warning, this command failed.\n")
36169689Skan
37169689Skan
38169689Skan/* Structures for handling Tree Browser's commands.  */
39169689Skan#define DEFTBCODE(COMMAND, STRING, HELP)   COMMAND,
40169689Skanenum TB_Comm_code {
41169689Skan#include "tree-browser.def"
42169689Skan  TB_UNUSED_COMMAND
43169689Skan};
44169689Skan#undef DEFTBCODE
45169689Skantypedef enum TB_Comm_code TB_CODE;
46169689Skan
47169689Skanstruct tb_command {
48169689Skan  const char *help_msg;
49169689Skan  const char *comm_text;
50169689Skan  size_t comm_len;
51169689Skan  TB_CODE comm_code;
52169689Skan};
53169689Skan
54169689Skan#define DEFTBCODE(code, str, help) { help, str, sizeof(str) - 1, code },
55169689Skanstatic const struct tb_command tb_commands[] =
56169689Skan{
57169689Skan#include "tree-browser.def"
58169689Skan};
59169689Skan#undef DEFTBCODE
60169689Skan
61169689Skan#define TB_COMMAND_LEN(N) (tb_commands[N].comm_len)
62169689Skan#define TB_COMMAND_TEXT(N) (tb_commands[N].comm_text)
63169689Skan#define TB_COMMAND_CODE(N) (tb_commands[N].comm_code)
64169689Skan#define TB_COMMAND_HELP(N) (tb_commands[N].help_msg)
65169689Skan
66169689Skan
67169689Skan/* Next structure is for parsing TREE_CODEs.  */
68169689Skanstruct tb_tree_code {
69169689Skan  enum tree_code code;
70169689Skan  const char *code_string;
71169689Skan  size_t code_string_len;
72169689Skan};
73169689Skan
74169689Skan#define DEFTREECODE(SYM, STRING, TYPE, NARGS) { SYM, STRING, sizeof (STRING) - 1 },
75169689Skanstatic const struct tb_tree_code tb_tree_codes[] =
76169689Skan{
77169689Skan#include "tree.def"
78169689Skan};
79169689Skan#undef DEFTREECODE
80169689Skan
81169689Skan#define TB_TREE_CODE(N) (tb_tree_codes[N].code)
82169689Skan#define TB_TREE_CODE_TEXT(N) (tb_tree_codes[N].code_string)
83169689Skan#define TB_TREE_CODE_LEN(N) (tb_tree_codes[N].code_string_len)
84169689Skan
85169689Skan
86169689Skan/* Function declarations.  */
87169689Skan
88169689Skanstatic long TB_getline (char **, long *, FILE *);
89169689Skanstatic TB_CODE TB_get_command (char *);
90169689Skanstatic enum tree_code TB_get_tree_code (char *);
91169689Skanstatic tree find_node_with_code (tree *, int *, void *);
92169689Skanstatic tree store_child_info (tree *, int *, void *);
93169689Skanstatic void TB_update_up (tree);
94169689Skanstatic tree TB_current_chain_node (tree);
95169689Skanstatic tree TB_prev_expr (tree);
96169689Skanstatic tree TB_next_expr (tree);
97169689Skanstatic tree TB_up_expr (tree);
98169689Skanstatic tree TB_first_in_bind (tree);
99169689Skanstatic tree TB_last_in_bind (tree);
100169689Skanstatic int  TB_parent_eq (const void *, const void *);
101169689Skanstatic tree TB_history_prev (void);
102169689Skan
103169689Skan/* FIXME: To be declared in a .h file.  */
104169689Skanvoid browse_tree (tree);
105169689Skan
106169689Skan/* Static variables.  */
107169689Skanstatic htab_t TB_up_ht;
108169689Skanstatic tree TB_history_stack = NULL_TREE;
109169689Skanstatic int TB_verbose = 1;
110169689Skan
111169689Skan
112169689Skan/* Entry point in the Tree Browser.  */
113169689Skan
114169689Skanvoid
115169689Skanbrowse_tree (tree begin)
116169689Skan{
117169689Skan  tree head;
118169689Skan  TB_CODE tbc = TB_UNUSED_COMMAND;
119169689Skan  ssize_t rd;
120169689Skan  char *input = NULL;
121169689Skan  long input_size = 0;
122169689Skan
123169689Skan  fprintf (TB_OUT_FILE, "\nTree Browser\n");
124169689Skan
125169689Skan#define TB_SET_HEAD(N) do {                                           \
126169689Skan  TB_history_stack = tree_cons (NULL_TREE, (N), TB_history_stack);    \
127169689Skan  head = N;                                                           \
128169689Skan  if (TB_verbose)                                                     \
129169689Skan    if (head)                                                         \
130169689Skan      {                                                               \
131169689Skan	print_generic_expr (TB_OUT_FILE, head, 0);                    \
132169689Skan	fprintf (TB_OUT_FILE, "\n");                                  \
133169689Skan      }                                                               \
134169689Skan} while (0)
135169689Skan
136169689Skan  TB_SET_HEAD (begin);
137169689Skan
138169689Skan  /* Store in a hashtable information about previous and upper statements.  */
139169689Skan  {
140169689Skan    TB_up_ht = htab_create (1023, htab_hash_pointer, &TB_parent_eq, NULL);
141169689Skan    TB_update_up (head);
142169689Skan  }
143169689Skan
144169689Skan  while (24)
145169689Skan    {
146169689Skan      fprintf (TB_OUT_FILE, "TB> ");
147169689Skan      rd = TB_getline (&input, &input_size, TB_IN_FILE);
148169689Skan
149169689Skan      if (rd == -1)
150169689Skan	/* EOF.  */
151169689Skan	goto ret;
152169689Skan
153169689Skan      if (rd != 1)
154169689Skan	/* Get a new command.  Otherwise the user just pressed enter, and thus
155169689Skan	   she expects the last command to be reexecuted.  */
156169689Skan	tbc = TB_get_command (input);
157169689Skan
158169689Skan      switch (tbc)
159169689Skan	{
160169689Skan	case TB_UPDATE_UP:
161169689Skan	  TB_update_up (head);
162169689Skan	  break;
163169689Skan
164169689Skan	case TB_MAX:
165169689Skan	  if (head && (INTEGRAL_TYPE_P (head)
166169689Skan		       || TREE_CODE (head) == REAL_TYPE))
167169689Skan	    TB_SET_HEAD (TYPE_MAX_VALUE (head));
168169689Skan	  else
169169689Skan	    TB_WF;
170169689Skan	  break;
171169689Skan
172169689Skan	case TB_MIN:
173169689Skan	  if (head && (INTEGRAL_TYPE_P (head)
174169689Skan		       || TREE_CODE (head) == REAL_TYPE))
175169689Skan	    TB_SET_HEAD (TYPE_MIN_VALUE (head));
176169689Skan	  else
177169689Skan	    TB_WF;
178169689Skan	  break;
179169689Skan
180169689Skan	case TB_ELT:
181169689Skan	  if (head && TREE_CODE (head) == TREE_VEC)
182169689Skan	    {
183169689Skan	      /* This command takes another argument: the element number:
184169689Skan		 for example "elt 1".  */
185169689Skan	      TB_NIY;
186169689Skan	    }
187169689Skan	  else if (head && TREE_CODE (head) == VECTOR_CST)
188169689Skan	    {
189169689Skan	      /* This command takes another argument: the element number:
190169689Skan                 for example "elt 1".  */
191169689Skan              TB_NIY;
192169689Skan	    }
193169689Skan	  else
194169689Skan	    TB_WF;
195169689Skan	  break;
196169689Skan
197169689Skan	case TB_VALUE:
198169689Skan	  if (head && TREE_CODE (head) == TREE_LIST)
199169689Skan	    TB_SET_HEAD (TREE_VALUE (head));
200169689Skan	  else
201169689Skan	    TB_WF;
202169689Skan	  break;
203169689Skan
204169689Skan	case TB_PURPOSE:
205169689Skan	  if (head && TREE_CODE (head) == TREE_LIST)
206169689Skan	    TB_SET_HEAD (TREE_PURPOSE (head));
207169689Skan	  else
208169689Skan	    TB_WF;
209169689Skan	  break;
210169689Skan
211169689Skan	case TB_IMAG:
212169689Skan	  if (head && TREE_CODE (head) == COMPLEX_CST)
213169689Skan	    TB_SET_HEAD (TREE_IMAGPART (head));
214169689Skan	  else
215169689Skan	    TB_WF;
216169689Skan	  break;
217169689Skan
218169689Skan	case TB_REAL:
219169689Skan	  if (head && TREE_CODE (head) == COMPLEX_CST)
220169689Skan	    TB_SET_HEAD (TREE_REALPART (head));
221169689Skan	  else
222169689Skan	    TB_WF;
223169689Skan	  break;
224169689Skan
225169689Skan	case TB_BLOCK:
226169689Skan	  if (head && TREE_CODE (head) == BIND_EXPR)
227169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 2));
228169689Skan	  else
229169689Skan	    TB_WF;
230169689Skan	  break;
231169689Skan
232169689Skan	case TB_SUBBLOCKS:
233169689Skan	  if (head && TREE_CODE (head) == BLOCK)
234169689Skan	    TB_SET_HEAD (BLOCK_SUBBLOCKS (head));
235169689Skan	  else
236169689Skan	    TB_WF;
237169689Skan	  break;
238169689Skan
239169689Skan	case TB_SUPERCONTEXT:
240169689Skan	  if (head && TREE_CODE (head) == BLOCK)
241169689Skan	    TB_SET_HEAD (BLOCK_SUPERCONTEXT (head));
242169689Skan	  else
243169689Skan	    TB_WF;
244169689Skan	  break;
245169689Skan
246169689Skan	case TB_VARS:
247169689Skan	  if (head && TREE_CODE (head) == BLOCK)
248169689Skan	    TB_SET_HEAD (BLOCK_VARS (head));
249169689Skan	  else if (head && TREE_CODE (head) == BIND_EXPR)
250169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 0));
251169689Skan	  else
252169689Skan	    TB_WF;
253169689Skan	  break;
254169689Skan
255169689Skan	case TB_REFERENCE_TO_THIS:
256169689Skan	  if (head && TYPE_P (head))
257169689Skan	    TB_SET_HEAD (TYPE_REFERENCE_TO (head));
258169689Skan	  else
259169689Skan	    TB_WF;
260169689Skan	  break;
261169689Skan
262169689Skan	case TB_POINTER_TO_THIS:
263169689Skan	  if (head && TYPE_P (head))
264169689Skan	    TB_SET_HEAD (TYPE_POINTER_TO (head));
265169689Skan	  else
266169689Skan	    TB_WF;
267169689Skan	  break;
268169689Skan
269169689Skan	case TB_BASETYPE:
270169689Skan	  if (head && TREE_CODE (head) == OFFSET_TYPE)
271169689Skan	    TB_SET_HEAD (TYPE_OFFSET_BASETYPE (head));
272169689Skan	  else
273169689Skan	    TB_WF;
274169689Skan	  break;
275169689Skan
276169689Skan	case TB_ARG_TYPES:
277169689Skan	  if (head && (TREE_CODE (head) == FUNCTION_TYPE
278169689Skan		       || TREE_CODE (head) == METHOD_TYPE))
279169689Skan	    TB_SET_HEAD (TYPE_ARG_TYPES (head));
280169689Skan	  else
281169689Skan	    TB_WF;
282169689Skan	  break;
283169689Skan
284169689Skan	case TB_METHOD_BASE_TYPE:
285169689Skan	  if (head && (TREE_CODE (head) == FUNCTION_TYPE
286169689Skan		       || TREE_CODE (head) == METHOD_TYPE)
287169689Skan	      && TYPE_METHOD_BASETYPE (head))
288169689Skan	    TB_SET_HEAD (TYPE_METHOD_BASETYPE (head));
289169689Skan	  else
290169689Skan	    TB_WF;
291169689Skan	  break;
292169689Skan
293169689Skan	case TB_FIELDS:
294169689Skan	  if (head && (TREE_CODE (head) == RECORD_TYPE
295169689Skan		       || TREE_CODE (head) == UNION_TYPE
296169689Skan		       || TREE_CODE (head) == QUAL_UNION_TYPE))
297169689Skan	    TB_SET_HEAD (TYPE_FIELDS (head));
298169689Skan	  else
299169689Skan	    TB_WF;
300169689Skan	  break;
301169689Skan
302169689Skan	case TB_DOMAIN:
303169689Skan	  if (head && TREE_CODE (head) == ARRAY_TYPE)
304169689Skan	    TB_SET_HEAD (TYPE_DOMAIN (head));
305169689Skan	  else
306169689Skan	    TB_WF;
307169689Skan	  break;
308169689Skan
309169689Skan	case TB_VALUES:
310169689Skan	  if (head && TREE_CODE (head) == ENUMERAL_TYPE)
311169689Skan	    TB_SET_HEAD (TYPE_VALUES (head));
312169689Skan	  else
313169689Skan	    TB_WF;
314169689Skan	  break;
315169689Skan
316169689Skan	case TB_ARG_TYPE:
317169689Skan	  if (head && TREE_CODE (head) == PARM_DECL)
318169689Skan	    TB_SET_HEAD (DECL_ARG_TYPE (head));
319169689Skan	  else
320169689Skan	    TB_WF;
321169689Skan	  break;
322169689Skan
323169689Skan	case TB_INITIAL:
324169689Skan	  if (head && DECL_P (head))
325169689Skan	    TB_SET_HEAD (DECL_INITIAL (head));
326169689Skan	  else
327169689Skan	    TB_WF;
328169689Skan	  break;
329169689Skan
330169689Skan	case TB_RESULT:
331169689Skan	  if (head && DECL_P (head))
332169689Skan	    TB_SET_HEAD (DECL_RESULT_FLD (head));
333169689Skan	  else
334169689Skan	    TB_WF;
335169689Skan	  break;
336169689Skan
337169689Skan	case TB_ARGUMENTS:
338169689Skan	  if (head && DECL_P (head))
339169689Skan	    TB_SET_HEAD (DECL_ARGUMENTS (head));
340169689Skan	  else
341169689Skan	    TB_WF;
342169689Skan	  break;
343169689Skan
344169689Skan	case TB_ABSTRACT_ORIGIN:
345169689Skan	  if (head && DECL_P (head))
346169689Skan	    TB_SET_HEAD (DECL_ABSTRACT_ORIGIN (head));
347169689Skan	  else if (head && TREE_CODE (head) == BLOCK)
348169689Skan	    TB_SET_HEAD (BLOCK_ABSTRACT_ORIGIN (head));
349169689Skan	  else
350169689Skan	    TB_WF;
351169689Skan	  break;
352169689Skan
353169689Skan	case TB_ATTRIBUTES:
354169689Skan	  if (head && DECL_P (head))
355169689Skan	    TB_SET_HEAD (DECL_ATTRIBUTES (head));
356169689Skan	  else if (head && TYPE_P (head))
357169689Skan	    TB_SET_HEAD (TYPE_ATTRIBUTES (head));
358169689Skan	  else
359169689Skan	    TB_WF;
360169689Skan	  break;
361169689Skan
362169689Skan	case TB_CONTEXT:
363169689Skan	  if (head && DECL_P (head))
364169689Skan	    TB_SET_HEAD (DECL_CONTEXT (head));
365169689Skan	  else if (head && TYPE_P (head)
366169689Skan		   && TYPE_CONTEXT (head))
367169689Skan	    TB_SET_HEAD (TYPE_CONTEXT (head));
368169689Skan	  else
369169689Skan	    TB_WF;
370169689Skan	  break;
371169689Skan
372169689Skan	case TB_OFFSET:
373169689Skan	  if (head && TREE_CODE (head) == FIELD_DECL)
374169689Skan	    TB_SET_HEAD (DECL_FIELD_OFFSET (head));
375169689Skan	  else
376169689Skan	    TB_WF;
377169689Skan	  break;
378169689Skan
379169689Skan	case TB_BIT_OFFSET:
380169689Skan	  if (head && TREE_CODE (head) == FIELD_DECL)
381169689Skan	    TB_SET_HEAD (DECL_FIELD_BIT_OFFSET (head));
382169689Skan	  else
383169689Skan	    TB_WF;
384169689Skan          break;
385169689Skan
386169689Skan	case TB_UNIT_SIZE:
387169689Skan	  if (head && DECL_P (head))
388169689Skan	    TB_SET_HEAD (DECL_SIZE_UNIT (head));
389169689Skan	  else if (head && TYPE_P (head))
390169689Skan	    TB_SET_HEAD (TYPE_SIZE_UNIT (head));
391169689Skan	  else
392169689Skan	    TB_WF;
393169689Skan	  break;
394169689Skan
395169689Skan	case TB_SIZE:
396169689Skan	  if (head && DECL_P (head))
397169689Skan	    TB_SET_HEAD (DECL_SIZE (head));
398169689Skan	  else if (head && TYPE_P (head))
399169689Skan	    TB_SET_HEAD (TYPE_SIZE (head));
400169689Skan	  else
401169689Skan	    TB_WF;
402169689Skan	  break;
403169689Skan
404169689Skan	case TB_TYPE:
405169689Skan	  if (head && TREE_TYPE (head))
406169689Skan	    TB_SET_HEAD (TREE_TYPE (head));
407169689Skan	  else
408169689Skan	    TB_WF;
409169689Skan	  break;
410169689Skan
411169689Skan	case TB_DECL_SAVED_TREE:
412169689Skan	  if (head && TREE_CODE (head) == FUNCTION_DECL
413169689Skan	      && DECL_SAVED_TREE (head))
414169689Skan	    TB_SET_HEAD (DECL_SAVED_TREE (head));
415169689Skan	  else
416169689Skan	    TB_WF;
417169689Skan	  break;
418169689Skan
419169689Skan	case TB_BODY:
420169689Skan	  if (head && TREE_CODE (head) == BIND_EXPR)
421169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 1));
422169689Skan	  else
423169689Skan	    TB_WF;
424169689Skan	  break;
425169689Skan
426169689Skan	case TB_CHILD_0:
427169689Skan	  if (head && EXPR_P (head) && TREE_OPERAND (head, 0))
428169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 0));
429169689Skan	  else
430169689Skan	    TB_WF;
431169689Skan	  break;
432169689Skan
433169689Skan	case TB_CHILD_1:
434169689Skan          if (head && EXPR_P (head) && TREE_OPERAND (head, 1))
435169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 1));
436169689Skan	  else
437169689Skan	    TB_WF;
438169689Skan          break;
439169689Skan
440169689Skan	case TB_CHILD_2:
441169689Skan          if (head && EXPR_P (head) && TREE_OPERAND (head, 2))
442169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 2));
443169689Skan	  else
444169689Skan	    TB_WF;
445169689Skan	  break;
446169689Skan
447169689Skan	case TB_CHILD_3:
448169689Skan	  if (head && EXPR_P (head) && TREE_OPERAND (head, 3))
449169689Skan	    TB_SET_HEAD (TREE_OPERAND (head, 3));
450169689Skan	  else
451169689Skan	    TB_WF;
452169689Skan          break;
453169689Skan
454169689Skan	case TB_PRINT:
455169689Skan	  if (head)
456169689Skan	    debug_tree (head);
457169689Skan	  else
458169689Skan	    TB_WF;
459169689Skan	  break;
460169689Skan
461169689Skan	case TB_PRETTY_PRINT:
462169689Skan	  if (head)
463169689Skan	    {
464169689Skan	      print_generic_stmt (TB_OUT_FILE, head, 0);
465169689Skan	      fprintf (TB_OUT_FILE, "\n");
466169689Skan	    }
467169689Skan	  else
468169689Skan	    TB_WF;
469169689Skan	  break;
470169689Skan
471169689Skan	case TB_SEARCH_NAME:
472169689Skan
473169689Skan	  break;
474169689Skan
475169689Skan	case TB_SEARCH_CODE:
476169689Skan	  {
477169689Skan	    enum tree_code code;
478169689Skan	    char *arg_text;
479169689Skan
480169689Skan	    arg_text = strchr (input, ' ');
481169689Skan	    if (arg_text == NULL)
482169689Skan	      {
483169689Skan		fprintf (TB_OUT_FILE, "First argument is missing.  This isn't a valid search command.  \n");
484169689Skan		break;
485169689Skan	      }
486169689Skan	    code = TB_get_tree_code (arg_text + 1);
487169689Skan
488169689Skan	    /* Search in the subtree a node with the given code.  */
489169689Skan	    {
490169689Skan	      tree res;
491169689Skan
492169689Skan	      res = walk_tree (&head, find_node_with_code, &code, NULL);
493169689Skan	      if (res == NULL_TREE)
494169689Skan		{
495169689Skan		  fprintf (TB_OUT_FILE, "There's no node with this code (reachable via the walk_tree function from this node).\n");
496169689Skan		}
497169689Skan	      else
498169689Skan		{
499169689Skan		  fprintf (TB_OUT_FILE, "Achoo!  I got this node in the tree.\n");
500169689Skan		  TB_SET_HEAD (res);
501169689Skan		}
502169689Skan	    }
503169689Skan	    break;
504169689Skan	  }
505169689Skan
506169689Skan#define TB_MOVE_HEAD(FCT) do {       \
507169689Skan  if (head)                          \
508169689Skan    {                                \
509169689Skan      tree t;                        \
510169689Skan      t = FCT (head);                \
511169689Skan      if (t)                         \
512169689Skan        TB_SET_HEAD (t);             \
513169689Skan      else                           \
514169689Skan	TB_WF;                       \
515169689Skan    }                                \
516169689Skan  else                               \
517169689Skan    TB_WF;                           \
518169689Skan} while (0)
519169689Skan
520169689Skan	case TB_FIRST:
521169689Skan	  TB_MOVE_HEAD (TB_first_in_bind);
522169689Skan          break;
523169689Skan
524169689Skan        case TB_LAST:
525169689Skan          TB_MOVE_HEAD (TB_last_in_bind);
526169689Skan          break;
527169689Skan
528169689Skan	case TB_UP:
529169689Skan	  TB_MOVE_HEAD (TB_up_expr);
530169689Skan	  break;
531169689Skan
532169689Skan	case TB_PREV:
533169689Skan	  TB_MOVE_HEAD (TB_prev_expr);
534169689Skan	  break;
535169689Skan
536169689Skan	case TB_NEXT:
537169689Skan	  TB_MOVE_HEAD (TB_next_expr);
538169689Skan	  break;
539169689Skan
540169689Skan	case TB_HPREV:
541169689Skan	  /* This command is a little bit special, since it deals with history
542169689Skan	     stack.  For this reason it should keep the "head = ..." statement
543169689Skan	     and not use TB_MOVE_HEAD.  */
544169689Skan	  if (head)
545169689Skan	    {
546169689Skan	      tree t;
547169689Skan	      t = TB_history_prev ();
548169689Skan	      if (t)
549169689Skan		{
550169689Skan		  head = t;
551169689Skan		  if (TB_verbose)
552169689Skan		    {
553169689Skan		      print_generic_expr (TB_OUT_FILE, head, 0);
554169689Skan		      fprintf (TB_OUT_FILE, "\n");
555169689Skan		    }
556169689Skan		}
557169689Skan	      else
558169689Skan		TB_WF;
559169689Skan	    }
560169689Skan	  else
561169689Skan	    TB_WF;
562169689Skan	  break;
563169689Skan
564169689Skan	case TB_CHAIN:
565169689Skan	  /* Don't go further if it's the last node in this chain.  */
566169689Skan	  if (head && TREE_CODE (head) == BLOCK)
567169689Skan	    TB_SET_HEAD (BLOCK_CHAIN (head));
568169689Skan	  else if (head && TREE_CHAIN (head))
569169689Skan	    TB_SET_HEAD (TREE_CHAIN (head));
570169689Skan	  else
571169689Skan	    TB_WF;
572169689Skan	  break;
573169689Skan
574169689Skan	case TB_FUN:
575169689Skan	  /* Go up to the current function declaration.  */
576169689Skan	  TB_SET_HEAD (current_function_decl);
577169689Skan	  fprintf (TB_OUT_FILE, "Current function declaration.\n");
578169689Skan	  break;
579169689Skan
580169689Skan	case TB_HELP:
581169689Skan	  /* Display a help message.  */
582169689Skan	  {
583169689Skan	    int i;
584169689Skan	    fprintf (TB_OUT_FILE, "Possible commands are:\n\n");
585169689Skan	    for (i = 0; i < TB_UNUSED_COMMAND; i++)
586169689Skan	      {
587169689Skan		fprintf (TB_OUT_FILE, "%20s  -  %s\n", TB_COMMAND_TEXT (i), TB_COMMAND_HELP (i));
588169689Skan	      }
589169689Skan	  }
590169689Skan	  break;
591169689Skan
592169689Skan	case TB_VERBOSE:
593169689Skan	  if (TB_verbose == 0)
594169689Skan	    {
595169689Skan	      TB_verbose = 1;
596169689Skan	      fprintf (TB_OUT_FILE, "Verbose on.\n");
597169689Skan	    }
598169689Skan	  else
599169689Skan	    {
600169689Skan	      TB_verbose = 0;
601169689Skan	      fprintf (TB_OUT_FILE, "Verbose off.\n");
602169689Skan	    }
603169689Skan	  break;
604169689Skan
605169689Skan	case TB_EXIT:
606169689Skan	case TB_QUIT:
607169689Skan	  /* Just exit from this function.  */
608169689Skan	  goto ret;
609169689Skan
610169689Skan	default:
611169689Skan	  TB_NIY;
612169689Skan	}
613169689Skan    }
614169689Skan
615169689Skan ret:;
616169689Skan  htab_delete (TB_up_ht);
617169689Skan  return;
618169689Skan}
619169689Skan
620169689Skan
621169689Skan/* Search the first node in this BIND_EXPR.  */
622169689Skan
623169689Skanstatic tree
624169689SkanTB_first_in_bind (tree node)
625169689Skan{
626169689Skan  tree t;
627169689Skan
628169689Skan  if (node == NULL_TREE)
629169689Skan    return NULL_TREE;
630169689Skan
631169689Skan  while ((t = TB_prev_expr (node)))
632169689Skan    node = t;
633169689Skan
634169689Skan  return node;
635169689Skan}
636169689Skan
637169689Skan/* Search the last node in this BIND_EXPR.  */
638169689Skan
639169689Skanstatic tree
640169689SkanTB_last_in_bind (tree node)
641169689Skan{
642169689Skan  tree t;
643169689Skan
644169689Skan  if (node == NULL_TREE)
645169689Skan    return NULL_TREE;
646169689Skan
647169689Skan  while ((t = TB_next_expr (node)))
648169689Skan    node = t;
649169689Skan
650169689Skan  return node;
651169689Skan}
652169689Skan
653169689Skan/* Search the parent expression for this node.  */
654169689Skan
655169689Skanstatic tree
656169689SkanTB_up_expr (tree node)
657169689Skan{
658169689Skan  tree res;
659169689Skan  if (node == NULL_TREE)
660169689Skan    return NULL_TREE;
661169689Skan
662169689Skan  res = (tree) htab_find (TB_up_ht, node);
663169689Skan  return res;
664169689Skan}
665169689Skan
666169689Skan/* Search the previous expression in this BIND_EXPR.  */
667169689Skan
668169689Skanstatic tree
669169689SkanTB_prev_expr (tree node)
670169689Skan{
671169689Skan  node = TB_current_chain_node (node);
672169689Skan
673169689Skan  if (node == NULL_TREE)
674169689Skan    return NULL_TREE;
675169689Skan
676169689Skan  node = TB_up_expr (node);
677169689Skan  if (node && TREE_CODE (node) == COMPOUND_EXPR)
678169689Skan    return node;
679169689Skan  else
680169689Skan    return NULL_TREE;
681169689Skan}
682169689Skan
683169689Skan/* Search the next expression in this BIND_EXPR.  */
684169689Skan
685169689Skanstatic tree
686169689SkanTB_next_expr (tree node)
687169689Skan{
688169689Skan  node = TB_current_chain_node (node);
689169689Skan
690169689Skan  if (node == NULL_TREE)
691169689Skan    return NULL_TREE;
692169689Skan
693169689Skan  node = TREE_OPERAND (node, 1);
694169689Skan  return node;
695169689Skan}
696169689Skan
697169689Skanstatic tree
698169689SkanTB_current_chain_node (tree node)
699169689Skan{
700169689Skan  if (node == NULL_TREE)
701169689Skan    return NULL_TREE;
702169689Skan
703169689Skan  if (TREE_CODE (node) == COMPOUND_EXPR)
704169689Skan    return node;
705169689Skan
706169689Skan  node = TB_up_expr (node);
707169689Skan  if (node)
708169689Skan    {
709169689Skan      if (TREE_CODE (node) == COMPOUND_EXPR)
710169689Skan	return node;
711169689Skan
712169689Skan      node = TB_up_expr (node);
713169689Skan      if (TREE_CODE (node) == COMPOUND_EXPR)
714169689Skan	return node;
715169689Skan    }
716169689Skan
717169689Skan  return NULL_TREE;
718169689Skan}
719169689Skan
720169689Skan/* For each node store in its children nodes that the current node is their
721169689Skan   parent.  This function is used by walk_tree.  */
722169689Skan
723169689Skanstatic tree
724169689Skanstore_child_info (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
725169689Skan		  void *data ATTRIBUTE_UNUSED)
726169689Skan{
727169689Skan  tree node;
728169689Skan  void **slot;
729169689Skan
730169689Skan  node = *tp;
731169689Skan
732169689Skan  /* 'node' is the parent of 'TREE_OPERAND (node, *)'.  */
733169689Skan  if (EXPRESSION_CLASS_P (node))
734169689Skan    {
735169689Skan
736169689Skan#define STORE_CHILD(N) do {                                                \
737169689Skan  tree op = TREE_OPERAND (node, N);                                        \
738169689Skan  slot = htab_find_slot (TB_up_ht, op, INSERT);                               \
739169689Skan  *slot = (void *) node;                                                   \
740169689Skan} while (0)
741169689Skan
742169689Skan      switch (TREE_CODE_LENGTH (TREE_CODE (node)))
743169689Skan	{
744169689Skan	case 4:
745169689Skan	  STORE_CHILD (0);
746169689Skan	  STORE_CHILD (1);
747169689Skan	  STORE_CHILD (2);
748169689Skan	  STORE_CHILD (3);
749169689Skan	  break;
750169689Skan
751169689Skan	case 3:
752169689Skan	  STORE_CHILD (0);
753169689Skan	  STORE_CHILD (1);
754169689Skan	  STORE_CHILD (2);
755169689Skan	  break;
756169689Skan
757169689Skan	case 2:
758169689Skan	  STORE_CHILD (0);
759169689Skan	  STORE_CHILD (1);
760169689Skan	  break;
761169689Skan
762169689Skan	case 1:
763169689Skan	  STORE_CHILD (0);
764169689Skan	  break;
765169689Skan
766169689Skan	case 0:
767169689Skan	default:
768169689Skan	  /* No children: nothing to do.  */
769169689Skan	  break;
770169689Skan	}
771169689Skan#undef STORE_CHILD
772169689Skan    }
773169689Skan
774169689Skan  /* Never stop walk_tree.  */
775169689Skan  return NULL_TREE;
776169689Skan}
777169689Skan
778169689Skan/* Function used in TB_up_ht.  */
779169689Skan
780169689Skanstatic int
781169689SkanTB_parent_eq (const void *p1, const void *p2)
782169689Skan{
783169689Skan  tree node, parent;
784169689Skan  node = (tree) p2;
785169689Skan  parent = (tree) p1;
786169689Skan
787169689Skan  if (p1 == NULL || p2 == NULL)
788169689Skan    return 0;
789169689Skan
790169689Skan  if (EXPRESSION_CLASS_P (parent))
791169689Skan    {
792169689Skan
793169689Skan#define TEST_CHILD(N) do {               \
794169689Skan  if (node == TREE_OPERAND (parent, N))  \
795169689Skan    return 1;                            \
796169689Skan} while (0)
797169689Skan
798169689Skan    switch (TREE_CODE_LENGTH (TREE_CODE (parent)))
799169689Skan      {
800169689Skan      case 4:
801169689Skan	TEST_CHILD (0);
802169689Skan	TEST_CHILD (1);
803169689Skan	TEST_CHILD (2);
804169689Skan	TEST_CHILD (3);
805169689Skan	break;
806169689Skan
807169689Skan      case 3:
808169689Skan	TEST_CHILD (0);
809169689Skan	TEST_CHILD (1);
810169689Skan	TEST_CHILD (2);
811169689Skan	break;
812169689Skan
813169689Skan      case 2:
814169689Skan	TEST_CHILD (0);
815169689Skan	TEST_CHILD (1);
816169689Skan	break;
817169689Skan
818169689Skan      case 1:
819169689Skan	TEST_CHILD (0);
820169689Skan	break;
821169689Skan
822169689Skan      case 0:
823169689Skan      default:
824169689Skan	/* No children: nothing to do.  */
825169689Skan	break;
826169689Skan      }
827169689Skan#undef TEST_CHILD
828169689Skan    }
829169689Skan
830169689Skan  return 0;
831169689Skan}
832169689Skan
833169689Skan/* Update information about upper expressions in the hash table.  */
834169689Skan
835169689Skanstatic void
836169689SkanTB_update_up (tree node)
837169689Skan{
838169689Skan  while (node)
839169689Skan    {
840169689Skan      walk_tree (&node, store_child_info, NULL, NULL);
841169689Skan
842169689Skan      /* Walk function's body.  */
843169689Skan      if (TREE_CODE (node) == FUNCTION_DECL)
844169689Skan        if (DECL_SAVED_TREE (node))
845169689Skan          walk_tree (&DECL_SAVED_TREE (node), store_child_info, NULL, NULL);
846169689Skan
847169689Skan      /* Walk rest of the chain.  */
848169689Skan      node = TREE_CHAIN (node);
849169689Skan    }
850169689Skan  fprintf (TB_OUT_FILE, "Up/prev expressions updated.\n");
851169689Skan}
852169689Skan
853169689Skan/* Parse the input string for determining the command the user asked for.  */
854169689Skan
855169689Skanstatic TB_CODE
856169689SkanTB_get_command (char *input)
857169689Skan{
858169689Skan  unsigned int mn, size_tok;
859169689Skan  int comp;
860169689Skan  char *space;
861169689Skan
862169689Skan  space = strchr (input, ' ');
863169689Skan  if (space != NULL)
864169689Skan    size_tok = strlen (input) - strlen (space);
865169689Skan  else
866169689Skan    size_tok = strlen (input) - 1;
867169689Skan
868169689Skan  for (mn = 0; mn < TB_UNUSED_COMMAND; mn++)
869169689Skan    {
870169689Skan      if (size_tok != TB_COMMAND_LEN (mn))
871169689Skan	continue;
872169689Skan
873169689Skan      comp = memcmp (input, TB_COMMAND_TEXT (mn), TB_COMMAND_LEN (mn));
874169689Skan      if (comp == 0)
875169689Skan	/* Here we just determined the command.  If this command takes
876169689Skan	   an argument, then the argument is determined later.  */
877169689Skan	return TB_COMMAND_CODE (mn);
878169689Skan    }
879169689Skan
880169689Skan  /* Not a valid command.  */
881169689Skan  return TB_UNUSED_COMMAND;
882169689Skan}
883169689Skan
884169689Skan/* Parse the input string for determining the tree code.  */
885169689Skan
886169689Skanstatic enum tree_code
887169689SkanTB_get_tree_code (char *input)
888169689Skan{
889169689Skan  unsigned int mn, size_tok;
890169689Skan  int comp;
891169689Skan  char *space;
892169689Skan
893169689Skan  space = strchr (input, ' ');
894169689Skan  if (space != NULL)
895169689Skan    size_tok = strlen (input) - strlen (space);
896169689Skan  else
897169689Skan    size_tok = strlen (input) - 1;
898169689Skan
899169689Skan  for (mn = 0; mn < LAST_AND_UNUSED_TREE_CODE; mn++)
900169689Skan    {
901169689Skan      if (size_tok != TB_TREE_CODE_LEN (mn))
902169689Skan	continue;
903169689Skan
904169689Skan      comp = memcmp (input, TB_TREE_CODE_TEXT (mn), TB_TREE_CODE_LEN (mn));
905169689Skan      if (comp == 0)
906169689Skan	{
907169689Skan	  fprintf (TB_OUT_FILE, "%s\n", TB_TREE_CODE_TEXT (mn));
908169689Skan	  return TB_TREE_CODE (mn);
909169689Skan	}
910169689Skan    }
911169689Skan
912169689Skan  /* This isn't a valid code.  */
913169689Skan  return LAST_AND_UNUSED_TREE_CODE;
914169689Skan}
915169689Skan
916169689Skan/* Find a node with a given code.  This function is used as an argument to
917169689Skan   walk_tree.  */
918169689Skan
919169689Skanstatic tree
920169689Skanfind_node_with_code (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
921169689Skan		     void *data)
922169689Skan{
923169689Skan  enum tree_code *code;
924169689Skan  code = (enum tree_code *) data;
925169689Skan  if (*code == TREE_CODE (*tp))
926169689Skan    return *tp;
927169689Skan
928169689Skan  return NULL_TREE;
929169689Skan}
930169689Skan
931169689Skan/* Returns a pointer to the last visited node.  */
932169689Skan
933169689Skanstatic tree
934169689SkanTB_history_prev (void)
935169689Skan{
936169689Skan  if (TB_history_stack)
937169689Skan    {
938169689Skan      TB_history_stack = TREE_CHAIN (TB_history_stack);
939169689Skan      if (TB_history_stack)
940169689Skan	return TREE_VALUE (TB_history_stack);
941169689Skan    }
942169689Skan  return NULL_TREE;
943169689Skan}
944169689Skan
945169689Skan/* Read up to (and including) a '\n' from STREAM into *LINEPTR
946169689Skan   (and null-terminate it). *LINEPTR is a pointer returned from malloc
947169689Skan   (or NULL), pointing to *N characters of space.  It is realloc'd as
948169689Skan   necessary.  Returns the number of characters read (not including the
949169689Skan   null terminator), or -1 on error or EOF.
950169689Skan   This function comes from sed (and is supposed to be a portable version
951169689Skan   of getline).  */
952169689Skan
953169689Skanstatic long
954169689SkanTB_getline (char **lineptr, long *n, FILE *stream)
955169689Skan{
956169689Skan  char *line, *p;
957169689Skan  long size, copy;
958169689Skan
959169689Skan  if (lineptr == NULL || n == NULL)
960169689Skan    {
961169689Skan      errno = EINVAL;
962169689Skan      return -1;
963169689Skan    }
964169689Skan
965169689Skan  if (ferror (stream))
966169689Skan    return -1;
967169689Skan
968169689Skan  /* Make sure we have a line buffer to start with.  */
969169689Skan  if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars.  */
970169689Skan    {
971169689Skan#ifndef MAX_CANON
972169689Skan#define MAX_CANON       256
973169689Skan#endif
974169689Skan      line = (char *) xrealloc (*lineptr, MAX_CANON);
975169689Skan      if (line == NULL)
976169689Skan        return -1;
977169689Skan      *lineptr = line;
978169689Skan      *n = MAX_CANON;
979169689Skan    }
980169689Skan
981169689Skan  line = *lineptr;
982169689Skan  size = *n;
983169689Skan
984169689Skan  copy = size;
985169689Skan  p = line;
986169689Skan
987169689Skan  while (1)
988169689Skan    {
989169689Skan      long len;
990169689Skan
991169689Skan      while (--copy > 0)
992169689Skan        {
993169689Skan          register int c = getc (stream);
994169689Skan          if (c == EOF)
995169689Skan            goto lose;
996169689Skan          else if ((*p++ = c) == '\n')
997169689Skan            goto win;
998169689Skan        }
999169689Skan
1000169689Skan      /* Need to enlarge the line buffer.  */
1001169689Skan      len = p - line;
1002169689Skan      size *= 2;
1003169689Skan      line = (char *) xrealloc (line, size);
1004169689Skan      if (line == NULL)
1005169689Skan        goto lose;
1006169689Skan      *lineptr = line;
1007169689Skan      *n = size;
1008169689Skan      p = line + len;
1009169689Skan      copy = size - len;
1010169689Skan    }
1011169689Skan
1012169689Skan lose:
1013169689Skan  if (p == *lineptr)
1014169689Skan    return -1;
1015169689Skan
1016169689Skan  /* Return a partial line since we got an error in the middle.  */
1017169689Skan win:
1018169689Skan#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(MSDOS)
1019169689Skan  if (p - 2 >= *lineptr && p[-2] == '\r')
1020169689Skan    p[-2] = p[-1], --p;
1021169689Skan#endif
1022169689Skan  *p = '\0';
1023169689Skan  return p - *lineptr;
1024169689Skan}
1025