OSDN Git Service

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