OSDN Git Service

* toplev.c: Fix formatting.
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
3    Written by Mark Mitchell <mark@codesourcery.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "tree.h"
25 #include "c-tree.h"
26 #include "splay-tree.h"
27 #include "diagnostic.h"
28 #include "toplev.h"
29 #include "tree-dump.h"
30 #include "langhooks.h"
31
32 static unsigned int queue PARAMS ((dump_info_p, tree, int));
33 static void dump_index PARAMS ((dump_info_p, unsigned int));
34 static void dequeue_and_dump PARAMS ((dump_info_p));
35 static void dump_new_line PARAMS ((dump_info_p));
36 static void dump_maybe_newline PARAMS ((dump_info_p));
37 static void dump_string_field PARAMS ((dump_info_p, const char *, const char *));
38
39 /* Add T to the end of the queue of nodes to dump.  Returns the index
40    assigned to T.  */
41
42 static unsigned int
43 queue (di, t, flags)
44      dump_info_p di;
45      tree t;
46      int flags;
47 {
48   dump_queue_p dq;
49   dump_node_info_p dni;
50   unsigned int index;
51
52   /* Assign the next available index to T.  */
53   index = ++di->index;
54
55   /* Obtain a new queue node.  */
56   if (di->free_list)
57     {
58       dq = di->free_list;
59       di->free_list = dq->next;
60     }
61   else
62     dq = (dump_queue_p) xmalloc (sizeof (struct dump_queue));
63
64   /* Create a new entry in the splay-tree.  */
65   dni = (dump_node_info_p) xmalloc (sizeof (struct dump_node_info));
66   dni->index = index;
67   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
68   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t, 
69                                 (splay_tree_value) dni);
70
71   /* Add it to the end of the queue.  */
72   dq->next = 0;
73   if (!di->queue_end)
74     di->queue = dq;
75   else
76     di->queue_end->next = dq;
77   di->queue_end = dq;
78
79   /* Return the index.  */
80   return index;
81 }
82
83 static void
84 dump_index (di, index)
85      dump_info_p di;
86      unsigned int index;
87 {
88   fprintf (di->stream, "@%-6u ", index);
89   di->column += 8;
90 }
91
92 /* If T has not already been output, queue it for subsequent output.
93    FIELD is a string to print before printing the index.  Then, the
94    index of T is printed.  */
95
96 void
97 queue_and_dump_index (di, field, t, flags)
98      dump_info_p di;
99      const char *field;
100      tree t;
101      int flags;
102 {
103   unsigned int index;
104   splay_tree_node n;
105
106   /* If there's no node, just return.  This makes for fewer checks in
107      our callers.  */
108   if (!t)
109     return;
110
111   /* See if we've already queued or dumped this node.  */
112   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
113   if (n)
114     index = ((dump_node_info_p) n->value)->index;
115   else
116     /* If we haven't, add it to the queue.  */
117     index = queue (di, t, flags);
118
119   /* Print the index of the node.  */
120   dump_maybe_newline (di);
121   fprintf (di->stream, "%-4s: ", field);
122   di->column += 6;
123   dump_index (di, index);
124 }
125
126 /* Dump the type of T.  */
127
128 void
129 queue_and_dump_type (di, t)
130      dump_info_p di;
131      tree t;
132 {
133   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
134 }
135
136 /* Dump column control */
137 #define SOL_COLUMN 25           /* Start of line column.  */
138 #define EOL_COLUMN 55           /* End of line column.  */
139 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
140
141 /* Insert a new line in the dump output, and indent to an appropriate
142    place to start printing more fields.  */
143
144 static void
145 dump_new_line (di)
146      dump_info_p di;
147 {
148   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
149   di->column = SOL_COLUMN;
150 }
151
152 /* If necessary, insert a new line.  */
153
154 static void
155 dump_maybe_newline (di)
156      dump_info_p di;
157 {
158   int extra;
159   
160   /* See if we need a new line.  */
161   if (di->column > EOL_COLUMN)
162     dump_new_line (di);
163   /* See if we need any padding.  */
164   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
165     {
166       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
167       di->column += COLUMN_ALIGNMENT - extra;
168     }
169 }
170
171 /* Dump pointer PTR using FIELD to identify it.  */
172
173 void
174 dump_pointer (di, field, ptr)
175      dump_info_p di;
176      const char *field;
177      void *ptr;
178 {
179   dump_maybe_newline (di);
180   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
181   di->column += 15;
182 }
183
184 /* Dump integer I using FIELD to identify it.  */
185
186 void
187 dump_int (di, field, i)
188      dump_info_p di;
189      const char *field;
190      int i;
191 {
192   dump_maybe_newline (di);
193   fprintf (di->stream, "%-4s: %-7d ", field, i);
194   di->column += 14;
195 }
196
197 /* Dump the string S.  */
198
199 void
200 dump_string (di, string)
201      dump_info_p di;
202      const char *string;
203 {
204   dump_maybe_newline (di);
205   fprintf (di->stream, "%-13s ", string);
206   if (strlen (string) > 13)
207     di->column += strlen (string) + 1;
208   else
209     di->column += 14;
210 }
211
212 /* Dump the string field S.  */
213
214 static void
215 dump_string_field (di, field, string)
216      dump_info_p di;
217      const char *field;
218      const char *string;
219 {
220   dump_maybe_newline (di);
221   fprintf (di->stream, "%-4s: %-7s ", field, string);
222   if (strlen (string) > 7)
223     di->column += 6 + strlen (string) + 1;
224   else
225     di->column += 14;
226 }
227
228 /* Dump information common to statements from STMT.  */
229
230 void
231 dump_stmt (di, t)
232      dump_info_p di;
233      tree t;
234 {
235   dump_int (di, "line", STMT_LINENO (t));
236 }
237
238 /* Dump the next statement after STMT.  */
239
240 void
241 dump_next_stmt (di, t)
242      dump_info_p di;
243      tree t;
244 {
245   dump_child ("next", TREE_CHAIN (t));
246 }
247
248 /* Dump the next node in the queue.  */
249
250 static void 
251 dequeue_and_dump (di)
252      dump_info_p di;
253 {
254   dump_queue_p dq;
255   splay_tree_node stn;
256   dump_node_info_p dni;
257   tree t;
258   unsigned int index;
259   enum tree_code code;
260   char code_class;
261   const char* code_name;
262
263   /* Get the next node from the queue.  */
264   dq = di->queue;
265   stn = dq->node;
266   t = (tree) stn->key;
267   dni = (dump_node_info_p) stn->value;
268   index = dni->index;
269
270   /* Remove the node from the queue, and put it on the free list.  */
271   di->queue = dq->next;
272   if (!di->queue)
273     di->queue_end = 0;
274   dq->next = di->free_list;
275   di->free_list = dq;
276
277   /* Print the node index.  */
278   dump_index (di, index);
279   /* And the type of node this is.  */
280   if (dni->binfo_p)
281     code_name = "binfo";
282   else
283     code_name = tree_code_name[(int) TREE_CODE (t)];
284   fprintf (di->stream, "%-16s ", code_name);
285   di->column = 25;
286
287   /* Figure out what kind of node this is.  */
288   code = TREE_CODE (t);
289   code_class = TREE_CODE_CLASS (code);
290
291   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
292      more informative.  */
293   if (dni->binfo_p)
294     {
295       if (TREE_VIA_PUBLIC (t))
296         dump_string (di, "pub");
297       else if (TREE_VIA_PROTECTED (t))
298         dump_string (di, "prot");
299       else if (TREE_VIA_PRIVATE (t))
300         dump_string (di, "priv");
301       if (TREE_VIA_VIRTUAL (t))
302         dump_string (di, "virt");
303             
304       dump_child ("type", BINFO_TYPE (t));
305       dump_child ("base", BINFO_BASETYPES (t));
306
307       goto done;
308     }
309
310   /* We can knock off a bunch of expression nodes in exactly the same
311      way.  */
312   if (IS_EXPR_CODE_CLASS (code_class))
313     {
314       /* If we're dumping children, dump them now.  */
315       queue_and_dump_type (di, t);
316
317       switch (code_class)
318         {
319         case '1':
320           dump_child ("op 0", TREE_OPERAND (t, 0));
321           break;
322               
323         case '2':
324         case '<':
325           dump_child ("op 0", TREE_OPERAND (t, 0));
326           dump_child ("op 1", TREE_OPERAND (t, 1));
327           break;
328               
329         case 'e':
330           /* These nodes are handled explicitly below.  */
331           break;
332               
333         default:
334           abort ();
335         }
336     }
337   else if (DECL_P (t))
338     {
339       /* All declarations have names.  */
340       if (DECL_NAME (t))
341         dump_child ("name", DECL_NAME (t));
342       if (DECL_ASSEMBLER_NAME_SET_P (t) 
343           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
344         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
345       /* And types.  */
346       queue_and_dump_type (di, t);
347       dump_child ("scpe", DECL_CONTEXT (t));
348       /* And a source position.  */
349       if (DECL_SOURCE_FILE (t))
350         {
351           const char *filename = strrchr (DECL_SOURCE_FILE (t), '/');
352           if (!filename)
353             filename = DECL_SOURCE_FILE (t);
354           else
355             /* Skip the slash.  */
356             ++filename;
357
358           dump_maybe_newline (di);
359           fprintf (di->stream, "srcp: %s:%-6d ", filename, 
360                    DECL_SOURCE_LINE (t));
361           di->column += 6 + strlen (filename) + 8;
362         }
363       /* And any declaration can be compiler-generated.  */
364       if (DECL_ARTIFICIAL (t))
365         dump_string (di, "artificial");
366       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
367         dump_child ("chan", TREE_CHAIN (t));
368     }
369   else if (code_class == 't')
370     {
371       /* All types have qualifiers.  */
372       int quals = (*lang_hooks.tree_dump.type_quals) (t);
373       
374       if (quals != TYPE_UNQUALIFIED)
375         {
376           fprintf (di->stream, "qual: %c%c%c     ",
377                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
378                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
379                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
380           di->column += 14;
381         }
382
383       /* All types have associated declarations.  */
384       dump_child ("name", TYPE_NAME (t));
385
386       /* All types have a main variant.  */
387       if (TYPE_MAIN_VARIANT (t) != t)
388         dump_child ("unql", TYPE_MAIN_VARIANT (t));
389       
390       /* And sizes.  */
391       dump_child ("size", TYPE_SIZE (t));
392
393       /* All types have alignments.  */
394       dump_int (di, "algn", TYPE_ALIGN (t));
395     }
396   else if (code_class == 'c')
397     /* All constants can have types.  */
398     queue_and_dump_type (di, t);
399
400   /* Give the language-specific code a chance to print something.  If
401      it's completely taken care of things, don't bother printing
402      anything more ourselves.  */
403   if ((*lang_hooks.tree_dump.dump_tree) (di, t))
404     goto done;
405
406   /* Now handle the various kinds of nodes.  */
407   switch (code)
408     {
409       int i;
410
411     case IDENTIFIER_NODE:
412       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
413       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
414       break;
415
416     case TREE_LIST:
417       dump_child ("purp", TREE_PURPOSE (t));
418       dump_child ("valu", TREE_VALUE (t));
419       dump_child ("chan", TREE_CHAIN (t));
420       break;
421
422     case TREE_VEC:
423       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
424       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
425         {
426           char buffer[32];
427           sprintf (buffer, "%u", i);
428           dump_child (buffer, TREE_VEC_ELT (t, i));
429         }
430       break;
431
432     case INTEGER_TYPE:
433     case ENUMERAL_TYPE:
434       dump_int (di, "prec", TYPE_PRECISION (t));
435       if (TREE_UNSIGNED (t))
436         dump_string (di, "unsigned");
437       dump_child ("min", TYPE_MIN_VALUE (t));
438       dump_child ("max", TYPE_MAX_VALUE (t));
439
440       if (code == ENUMERAL_TYPE)
441         dump_child ("csts", TYPE_VALUES (t));
442       break;
443
444     case REAL_TYPE:
445       dump_int (di, "prec", TYPE_PRECISION (t));
446       break;
447
448     case POINTER_TYPE:
449       dump_child ("ptd", TREE_TYPE (t));
450       break;
451
452     case REFERENCE_TYPE:
453       dump_child ("refd", TREE_TYPE (t));
454       break;
455
456     case METHOD_TYPE:
457       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
458       /* Fall through.  */
459
460     case FUNCTION_TYPE:
461       dump_child ("retn", TREE_TYPE (t));
462       dump_child ("prms", TYPE_ARG_TYPES (t));
463       break;
464
465     case ARRAY_TYPE:
466       dump_child ("elts", TREE_TYPE (t));
467       dump_child ("domn", TYPE_DOMAIN (t));
468       break;
469
470     case RECORD_TYPE:
471     case UNION_TYPE:
472       if (TREE_CODE (t) == RECORD_TYPE)
473         dump_string (di, "struct");
474       else
475         dump_string (di, "union");
476       
477       dump_child ("flds", TYPE_FIELDS (t));
478       dump_child ("fncs", TYPE_METHODS (t));
479       queue_and_dump_index (di, "binf", TYPE_BINFO (t), 
480                             DUMP_BINFO);
481       break;
482
483     case CONST_DECL:
484       dump_child ("cnst", DECL_INITIAL (t));
485       break;
486
487     case VAR_DECL:
488     case PARM_DECL:
489     case FIELD_DECL:
490     case RESULT_DECL:
491       if (TREE_CODE (t) == PARM_DECL)
492         dump_child ("argt", DECL_ARG_TYPE (t));
493       else
494         dump_child ("init", DECL_INITIAL (t));
495       dump_child ("size", DECL_SIZE (t));
496       dump_int (di, "algn", DECL_ALIGN (t));
497
498       if (TREE_CODE (t) == FIELD_DECL)
499         {
500           if (DECL_C_BIT_FIELD (t))
501             dump_string (di, "bitfield");
502           if (DECL_FIELD_OFFSET (t))
503             dump_child ("bpos", bit_position (t));
504         }
505       else if (TREE_CODE (t) == VAR_DECL 
506                || TREE_CODE (t) == PARM_DECL)
507         {
508           dump_int (di, "used", TREE_USED (t));
509           if (DECL_REGISTER (t))
510             dump_string (di, "register");
511         }
512       break;
513
514     case FUNCTION_DECL:
515       dump_child ("args", DECL_ARGUMENTS (t));
516       if (DECL_EXTERNAL (t))
517         dump_string (di, "undefined");
518       if (TREE_PUBLIC (t))
519         dump_string (di, "extern");
520       else
521         dump_string (di, "static");
522       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
523         dump_child ("body", DECL_SAVED_TREE (t));
524       break;
525
526     case ASM_STMT:
527       dump_stmt (di, t);
528       if (ASM_VOLATILE_P (t))
529         dump_string (di, "volatile");
530       dump_child ("strg", ASM_STRING (t));
531       dump_child ("outs", ASM_OUTPUTS (t));
532       dump_child ("ins", ASM_INPUTS (t));
533       dump_child ("clbr", ASM_CLOBBERS (t));
534       dump_next_stmt (di, t);
535       break;
536
537     case BREAK_STMT:
538     case CONTINUE_STMT:
539       dump_stmt (di, t);
540       dump_next_stmt (di, t);
541       break;
542
543     case CASE_LABEL:
544       /* Note that a case label is not like other statements; there is
545          no way to get the line-number of a case label.  */
546       dump_child ("low", CASE_LOW (t));
547       dump_child ("high", CASE_HIGH (t));
548       dump_next_stmt (di, t);
549       break;
550
551     case COMPOUND_STMT:
552       dump_stmt (di, t);
553       dump_child ("body", COMPOUND_BODY (t));
554       dump_next_stmt (di, t);
555       break;
556
557     case DECL_STMT:
558       dump_stmt (di, t);
559       dump_child ("decl", DECL_STMT_DECL (t));
560       dump_next_stmt (di, t);
561       break;
562       
563     case DO_STMT:
564       dump_stmt (di, t);
565       dump_child ("body", DO_BODY (t));
566       dump_child ("cond", DO_COND (t));
567       dump_next_stmt (di, t);
568       break;
569
570     case EXPR_STMT:
571       dump_stmt (di, t);
572       dump_child ("expr", EXPR_STMT_EXPR (t));
573       dump_next_stmt (di, t);
574       break;
575
576     case FOR_STMT:
577       dump_stmt (di, t);
578       dump_child ("init", FOR_INIT_STMT (t));
579       dump_child ("cond", FOR_COND (t));
580       dump_child ("expr", FOR_EXPR (t));
581       dump_child ("body", FOR_BODY (t));
582       dump_next_stmt (di, t);
583       break;
584
585     case GOTO_STMT:
586       dump_stmt (di, t);
587       dump_child ("dest", GOTO_DESTINATION (t));
588       dump_next_stmt (di, t);
589       break;
590
591     case IF_STMT:
592       dump_stmt (di, t);
593       dump_child ("cond", IF_COND (t));
594       dump_child ("then", THEN_CLAUSE (t));
595       dump_child ("else", ELSE_CLAUSE (t));
596       dump_next_stmt (di, t);
597       break;
598
599     case LABEL_STMT:
600       dump_stmt (di, t);
601       dump_child ("labl", LABEL_STMT_LABEL (t));
602       dump_next_stmt (di, t);
603       break;
604
605     case RETURN_STMT:
606       dump_stmt (di, t);
607       dump_child ("expr", RETURN_EXPR (t));
608       dump_next_stmt (di, t);
609       break;
610
611     case SWITCH_STMT:
612       dump_stmt (di, t);
613       dump_child ("cond", SWITCH_COND (t));
614       dump_child ("body", SWITCH_BODY (t));
615       dump_next_stmt (di, t);
616       break;
617
618     case WHILE_STMT:
619       dump_stmt (di, t);
620       dump_child ("cond", WHILE_COND (t));
621       dump_child ("body", WHILE_BODY (t));
622       dump_next_stmt (di, t);
623       break;
624
625     case SCOPE_STMT:
626       dump_stmt (di, t);
627       if (SCOPE_BEGIN_P (t))
628         dump_string (di, "begn");
629       else
630         dump_string (di, "end");
631       if (SCOPE_NULLIFIED_P (t))
632         dump_string (di, "null");
633       if (!SCOPE_NO_CLEANUPS_P (t))
634         dump_string (di, "clnp");
635       dump_next_stmt (di, t);
636       break;
637
638     case INTEGER_CST:
639       if (TREE_INT_CST_HIGH (t))
640         dump_int (di, "high", TREE_INT_CST_HIGH (t));
641       dump_int (di, "low", TREE_INT_CST_LOW (t));
642       break;
643
644     case STRING_CST:
645       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
646       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
647       break;
648
649     case TRUTH_NOT_EXPR:
650     case ADDR_EXPR:
651     case INDIRECT_REF:
652     case CLEANUP_POINT_EXPR:
653     case SAVE_EXPR:
654       /* These nodes are unary, but do not have code class `1'.  */
655       dump_child ("op 0", TREE_OPERAND (t, 0));
656       break;
657
658     case TRUTH_ANDIF_EXPR:
659     case TRUTH_ORIF_EXPR:
660     case INIT_EXPR:
661     case MODIFY_EXPR:
662     case COMPONENT_REF:
663     case COMPOUND_EXPR:
664     case ARRAY_REF:
665     case PREDECREMENT_EXPR:
666     case PREINCREMENT_EXPR:
667     case POSTDECREMENT_EXPR:
668     case POSTINCREMENT_EXPR:
669       /* These nodes are binary, but do not have code class `2'.  */
670       dump_child ("op 0", TREE_OPERAND (t, 0));
671       dump_child ("op 1", TREE_OPERAND (t, 1));
672       break;
673
674     case COND_EXPR:
675       dump_child ("op 0", TREE_OPERAND (t, 0));
676       dump_child ("op 1", TREE_OPERAND (t, 1));
677       dump_child ("op 2", TREE_OPERAND (t, 2));
678       break;
679
680     case CALL_EXPR:
681       dump_child ("fn", TREE_OPERAND (t, 0));
682       dump_child ("args", TREE_OPERAND (t, 1));
683       break;
684
685     case CONSTRUCTOR:
686       dump_child ("elts", TREE_OPERAND (t, 1));
687       break;
688
689     case STMT_EXPR:
690       dump_child ("stmt", STMT_EXPR_STMT (t));
691       break;
692
693     case BIND_EXPR:
694       dump_child ("vars", TREE_OPERAND (t, 0));
695       dump_child ("body", TREE_OPERAND (t, 1));
696       break;
697
698     case LOOP_EXPR:
699       dump_child ("body", TREE_OPERAND (t, 0));
700       break;
701
702     case EXIT_EXPR:
703       dump_child ("cond", TREE_OPERAND (t, 0));
704       break;
705
706     case TARGET_EXPR:
707       dump_child ("decl", TREE_OPERAND (t, 0));
708       dump_child ("init", TREE_OPERAND (t, 1));
709       dump_child ("clnp", TREE_OPERAND (t, 2));
710       /* There really are two possible places the initializer can be.
711          After RTL expansion, the second operand is moved to the
712          position of the fourth operand, and the second operand
713          becomes NULL.  */
714       dump_child ("init", TREE_OPERAND (t, 3));
715       break;
716       
717     case EXPR_WITH_FILE_LOCATION:
718       dump_child ("expr", EXPR_WFL_NODE (t));
719       break;
720
721     default:
722       /* There are no additional fields to print.  */
723       break;
724     }
725
726  done:
727   if (dump_flag (di, TDF_ADDRESS, NULL))
728     dump_pointer (di, "addr", (void *)t);
729   
730   /* Terminate the line.  */
731   fprintf (di->stream, "\n");
732 }
733
734 /* Return non-zero if FLAG has been specified for the dump, and NODE
735    is not the root node of the dump.  */
736
737 int dump_flag (di, flag, node)
738      dump_info_p di;
739      int flag;
740      tree node;
741 {
742   return (di->flags & flag) && (node != di->node);
743 }
744
745 /* Dump T, and all its children, on STREAM.  */
746
747 void
748 dump_node (t, flags, stream)
749      tree t;
750      int flags;
751      FILE *stream;
752 {
753   struct dump_info di;
754   dump_queue_p dq;
755   dump_queue_p next_dq;
756
757   /* Initialize the dump-information structure.  */
758   di.stream = stream;
759   di.index = 0;
760   di.column = 0;
761   di.queue = 0;
762   di.queue_end = 0;
763   di.free_list = 0;
764   di.flags = flags;
765   di.node = t;
766   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0, 
767                              (splay_tree_delete_value_fn) &free);
768
769   /* Queue up the first node.  */
770   queue (&di, t, DUMP_NONE);
771
772   /* Until the queue is empty, keep dumping nodes.  */
773   while (di.queue)
774     dequeue_and_dump (&di);
775
776   /* Now, clean up.  */
777   for (dq = di.free_list; dq; dq = next_dq)
778     {
779       next_dq = dq->next;
780       free (dq);
781     }
782   splay_tree_delete (di.nodes);
783 }
784
785 /* Define a tree dump switch.  */
786 struct dump_file_info
787 {
788   const char *const suffix;     /* suffix to give output file.  */
789   const char *const swtch;      /* command line switch */
790   int flags;                    /* user flags */
791   int state;                    /* state of play */
792 };
793
794 /* Table of tree dump switches. This must be consistent with the
795    TREE_DUMP_INDEX enumeration in tree.h */
796 static struct dump_file_info dump_files[TDI_end] =
797 {
798   {".tu", "dump-translation-unit", 0, 0},
799   {".class", "dump-class-hierarchy", 0, 0},
800   {".original", "dump-tree-original", 0, 0},
801   {".optimized", "dump-tree-optimized", 0, 0},
802   {".inlined", "dump-tree-inlined", 0, 0},
803 };
804
805 /* Define a name->number mapping for a dump flag value.  */
806 struct dump_option_value_info
807 {
808   const char *const name;       /* the name of the value */
809   const int value;              /* the value of the name */
810 };
811
812 /* Table of dump options. This must be consistent with the TDF_* flags
813    in tree.h */
814 static const struct dump_option_value_info dump_options[] =
815 {
816   {"address", TDF_ADDRESS},
817   {"slim", TDF_SLIM},
818   {"all", ~0},
819   {NULL, 0}
820 };
821
822 /* Begin a tree dump for PHASE. Stores any user supplied flag in
823    *FLAG_PTR and returns a stream to write to. If the dump is not
824    enabled, returns NULL.
825    Multiple calls will reopen and append to the dump file.  */
826
827 FILE *
828 dump_begin (phase, flag_ptr)
829      enum tree_dump_index phase;
830      int *flag_ptr;
831 {
832   FILE *stream;
833   char *name;
834   
835   if (!dump_files[phase].state)
836     return NULL;
837   
838   name = concat (dump_base_name, dump_files[phase].suffix, NULL);
839   stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
840   if (!stream)
841     error ("could not open dump file `%s'", name);
842   else
843     dump_files[phase].state = 1;
844   free (name);
845   if (flag_ptr)
846     *flag_ptr = dump_files[phase].flags;
847   
848   return stream;
849 }
850
851 /* Returns non-zero if tree dump PHASE is enabled.  */
852
853 int
854 dump_enabled_p (phase)
855      enum tree_dump_index phase;
856 {
857   return dump_files[phase].state;
858 }
859
860 /* Returns the switch name of PHASE.  */
861
862 const char *
863 dump_flag_name (phase)
864      enum tree_dump_index phase;
865 {
866   return dump_files[phase].swtch;
867 }
868
869 /* Finish a tree dump for PHASE. STREAM is the stream created by
870    dump_begin.  */
871
872 void
873 dump_end (phase, stream)
874      enum tree_dump_index phase ATTRIBUTE_UNUSED;
875      FILE *stream;
876 {
877   fclose (stream);
878 }
879
880 /* Parse ARG as a dump switch. Return non-zero if it is, and store the
881    relevant details in the dump_files array.  */
882
883 int
884 dump_switch_p (arg)
885      const char *arg;
886 {
887   unsigned ix;
888   const char *option_value;
889   
890   for (ix = 0; ix != TDI_end; ix++)
891     if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch)))
892       {
893         const char *ptr = option_value;
894         int flags = 0;
895         
896         while (*ptr)
897           {
898             const struct dump_option_value_info *option_ptr;
899             const char *end_ptr;
900             unsigned length;
901             
902             while (*ptr == '-')
903               ptr++;
904             end_ptr = strchr (ptr, '-');
905             if (!end_ptr)
906               end_ptr = ptr + strlen (ptr);
907             length = end_ptr - ptr;
908             
909             for (option_ptr = dump_options; option_ptr->name;
910                  option_ptr++)
911               if (strlen (option_ptr->name) == length
912                   && !memcmp (option_ptr->name, ptr, length))
913                 {
914                   flags |= option_ptr->value;
915                   goto found;
916                 }
917             warning ("ignoring unknown option `%.*s' in `-f%s'",
918                      length, ptr, dump_files[ix].swtch);
919           found:;
920             ptr = end_ptr;
921           }
922         
923         dump_files[ix].state = -1;
924         dump_files[ix].flags = flags;
925         
926         return 1;
927       }
928   return 0;
929 }