OSDN Git Service

* cp-tree.def (DECL_STMT): Make it smaller.
[pf3gnuchains/gcc-fork.git] / gcc / cp / dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999 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 /* TODO: Class types.
23          Binfos.  */
24
25 #include "config.h"
26 #include "system.h"
27 #include "tree.h"
28 #include "cp-tree.h"
29 #include "splay-tree.h"
30
31 /* Flags used with queue functions.  */
32 #define DUMP_NONE     0
33 #define DUMP_CHILDREN 1
34 #define DUMP_BINFO    2
35
36 /* Information about a node to be dumped.  */
37
38 typedef struct dump_node_info
39 {
40   /* The index for the node.  */
41   unsigned int index;
42   /* Nonzero if we should dump the children of the node.  */
43   unsigned int dump_children_p : 1;
44   /* Nonzero if the node is a binfo.  */
45   unsigned int binfo_p : 1;
46 } *dump_node_info_p;
47
48 /* A dump_queue is a link in the queue of things to be dumped.  */
49
50 typedef struct dump_queue
51 {
52   /* The queued tree node.  */
53   splay_tree_node node;
54   /* The next node in the queue.  */
55   struct dump_queue *next;
56 } *dump_queue_p;
57
58 /* A dump_info gives information about how we should perform the dump 
59    and about the current state of the dump.  */
60
61 typedef struct dump_info
62 {
63   /* The stream on which to dump the information.  */
64   FILE *stream;
65   /* The next unused node index.  */
66   unsigned int index;
67   /* The next column.  */
68   unsigned int column;
69   /* The first node in the queue of nodes to be written out.  */
70   dump_queue_p queue;
71   /* The last node in the queue.  */
72   dump_queue_p queue_end;
73   /* Free queue nodes.  */
74   dump_queue_p free_list;
75   /* The tree nodes which we have already written out.  The 
76      keys are the addresses of the nodes; the values are the integer
77      indices we assigned them.  */
78   splay_tree nodes;
79 } *dump_info_p;
80
81 static unsigned int queue PROTO ((dump_info_p, tree, int));
82 static void dump_index PROTO ((dump_info_p, unsigned int));
83 static void queue_and_dump_index PROTO ((dump_info_p, const char *, tree, int));
84 static void queue_and_dump_type PROTO ((dump_info_p, tree, int));
85 static void dequeue_and_dump PROTO ((dump_info_p));
86 static void dump_new_line PROTO ((dump_info_p));
87 static void dump_maybe_newline PROTO ((dump_info_p));
88 static void dump_int PROTO ((dump_info_p, const char *, int));
89 static void dump_string PROTO ((dump_info_p, const char *));
90 static void dump_string_field PROTO ((dump_info_p, const char *, const char *));
91 static void dump_node PROTO ((tree, FILE *));
92 static void dump_stmt PROTO ((dump_info_p, tree));
93
94 /* Add T to the end of the queue of nodes to dump.  If DUMP_CHILDREN_P
95    is non-zero, then its children should be dumped as well.  Returns
96    the index assigned to T.  */
97
98 static unsigned int
99 queue (di, t, flags)
100      dump_info_p di;
101      tree t;
102      int flags;
103 {
104   dump_queue_p dq;
105   dump_node_info_p dni;
106   unsigned int index;
107
108   /* Assign the next available index to T.  */
109   index = ++di->index;
110
111   /* Obtain a new queue node.  */
112   if (di->free_list)
113     {
114       dq = di->free_list;
115       di->free_list = dq->next;
116     }
117   else
118     dq = (dump_queue_p) xmalloc (sizeof (struct dump_queue));
119
120   /* Create a new entry in the splay-tree.  */
121   dni = (dump_node_info_p) xmalloc (sizeof (struct dump_node_info));
122   dni->index = index;
123   dni->dump_children_p = ((flags & DUMP_CHILDREN) != 0);
124   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
125   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t, 
126                                 (splay_tree_value) dni);
127
128   /* Add it to the end of the queue.  */
129   dq->next = 0;
130   if (!di->queue_end)
131     di->queue = dq;
132   else
133     di->queue_end->next = dq;
134   di->queue_end = dq;
135
136   /* Return the index.  */
137   return index;
138 }
139
140 static void
141 dump_index (di, index)
142      dump_info_p di;
143      unsigned int index;
144 {
145   fprintf (di->stream, "@%-6u ", index);
146   di->column += 8;
147 }
148
149 /* If T has not already been output, queue it for subsequent output.
150    FIELD is a string to print before printing the index.  Then, the
151    index of T is printed.  */
152
153 static void
154 queue_and_dump_index (di, field, t, flags)
155      dump_info_p di;
156      const char *field;
157      tree t;
158      int flags;
159 {
160   unsigned int index;
161   splay_tree_node n;
162
163   /* If there's no node, just return.  This makes for fewer checks in
164      our callers.  */
165   if (!t)
166     return;
167
168   /* See if we've already queued or dumped this node.  */
169   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
170   if (n)
171     index = ((dump_node_info_p) n->value)->index;
172   else
173     /* If we haven't, add it to the queue.  */
174     index = queue (di, t, flags);
175
176   /* Print the index of the node.  */
177   dump_maybe_newline (di);
178   fprintf (di->stream, "%-4s: ", field);
179   di->column += 6;
180   dump_index (di, index);
181 }
182
183 /* Dump the type of T.  */
184
185 static void
186 queue_and_dump_type (di, t, dump_children_p)
187      dump_info_p di;
188      tree t;
189      int dump_children_p;
190 {
191   queue_and_dump_index (di, "type", TREE_TYPE (t), dump_children_p);
192 }
193
194 /* Insert a new line in the dump output, and indent to an appropriate
195    place to start printing more fields.  */
196
197 static void
198 dump_new_line (di)
199      dump_info_p di;
200 {
201   fprintf (di->stream, "\n%25s", "");
202   di->column = 25;
203 }
204
205 /* If necessary, insert a new line.  */
206
207 static void
208 dump_maybe_newline (di)
209      dump_info_p di;
210 {
211   /* See if we need a new line.  */
212   if (di->column > 53)
213     dump_new_line (di);
214   /* See if we need any padding.  */
215   else if ((di->column - 25) % 14 != 0)
216     {
217       fprintf (di->stream, "%*s", 14 - ((di->column - 25) % 14), "");
218       di->column += 14 - (di->column - 25) % 14;
219     }
220 }
221
222 /* Dump I using FIELD to identity it.  */
223
224 static void
225 dump_int (di, field, i)
226      dump_info_p di;
227      const char *field;
228      int i;
229 {
230   dump_maybe_newline (di);
231   fprintf (di->stream, "%-4s: %-7d ", field, i);
232   di->column += 14;
233 }
234
235 /* Dump the string S.  */
236
237 static void
238 dump_string (di, string)
239      dump_info_p di;
240      const char *string;
241 {
242   dump_maybe_newline (di);
243   fprintf (di->stream, "%-13s ", string);
244   if (strlen (string) > 13)
245     di->column += strlen (string) + 1;
246   else
247     di->column += 14;
248 }
249
250 /* Dump the string field S.  */
251
252 static void
253 dump_string_field (di, field, string)
254      dump_info_p di;
255      const char *field;
256      const char *string;
257 {
258   dump_maybe_newline (di);
259   fprintf (di->stream, "%-4s: %-7s ", field, string);
260   if (strlen (string) > 7)
261     di->column += 6 + strlen (string) + 1;
262   else
263     di->column += 14;
264 }
265
266 /* Dump information common to statements from STMT.  */
267
268 static void
269 dump_stmt (di, t)
270      dump_info_p di;
271      tree t;
272 {
273   dump_int (di, "line", STMT_LINENO (t));
274 }
275
276 /* Dump the CHILD and its children.  */
277 #define dump_child(field, child) \
278   queue_and_dump_index (di, field, child, DUMP_CHILDREN)
279
280 /* Dump the next node in the queue.  */
281
282 static void 
283 dequeue_and_dump (di)
284      dump_info_p di;
285 {
286   dump_queue_p dq;
287   splay_tree_node stn;
288   dump_node_info_p dni;
289   tree t;
290   unsigned int index;
291   int dump_children_p;
292   enum tree_code code;
293   char code_class;
294   const char* code_name;
295
296   /* Get the next node from the queue.  */
297   dq = di->queue;
298   stn = dq->node;
299   t = (tree) stn->key;
300   dni = (dump_node_info_p) stn->value;
301   index = dni->index;
302   dump_children_p = dni->dump_children_p;
303
304   /* Remove the node from the queue, and put it on the free list.  */
305   di->queue = dq->next;
306   if (!di->queue)
307     di->queue_end = 0;
308   dq->next = di->free_list;
309   di->free_list = dq;
310
311   /* Print the node index.  */
312   dump_index (di, index);
313   /* And the type of node this is.  */
314   if (dni->binfo_p)
315     code_name = "binfo";
316   else
317     code_name = tree_code_name[(int) TREE_CODE (t)];
318   fprintf (di->stream, "%-16s ", code_name);
319   di->column = 25;
320
321   /* Figure out what kind of node this is.  */
322   code = TREE_CODE (t);
323   code_class = TREE_CODE_CLASS (code);
324
325   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
326      more informative.  */
327   if (dni->binfo_p)
328     {
329       if (TREE_VIA_PUBLIC (t))
330         dump_string (di, "pub");
331       else if (TREE_VIA_PROTECTED (t))
332         dump_string (di, "prot");
333       else if (TREE_VIA_PRIVATE (t))
334         dump_string (di, "priv");
335       if (TREE_VIA_VIRTUAL (t))
336         dump_string (di, "virt");
337             
338       if (dump_children_p) 
339         {
340           dump_child ("type", BINFO_TYPE (t));
341           dump_child ("base", BINFO_BASETYPES (t));
342         }
343
344       goto done;
345     }
346
347   /* We can knock off a bunch of expression nodes in exactly the same
348      way.  */
349   if (IS_EXPR_CODE_CLASS (code_class))
350     {
351       /* If we're dumping children, dump them now.  */
352       if (dump_children_p)
353         {
354           queue_and_dump_type (di, t, 1);
355
356           switch (code_class)
357             {
358             case '1':
359               dump_child ("op 0", TREE_OPERAND (t, 0));
360               break;
361               
362             case '2':
363             case '<':
364               dump_child ("op 0", TREE_OPERAND (t, 0));
365               dump_child ("op 1", TREE_OPERAND (t, 1));
366               break;
367               
368             case 'e':
369               /* These nodes are handled explicitly below.  */
370               break;
371               
372             default:
373               my_friendly_abort (19990726);
374             }
375         }
376     }
377   else if (code_class == 'd')
378     {
379       /* All declarations have names.  */
380       if (DECL_NAME (t))
381         dump_child ("name", DECL_NAME (t));
382       /* And types.  */
383       if (dump_children_p)
384         {
385           queue_and_dump_type (di, t, 1);
386           queue_and_dump_index (di, "scpe", DECL_CONTEXT (t), 0);
387         }
388       /* And a source position.  */
389       if (DECL_SOURCE_FILE (t))
390         {
391           const char *filename = rindex (DECL_SOURCE_FILE (t), '/');
392           if (!filename)
393             filename = DECL_SOURCE_FILE (t);
394           else
395             /* Skip the slash.  */
396             ++filename;
397
398           dump_maybe_newline (di);
399           fprintf (di->stream, "srcp: %s:%-6d ", filename, 
400                    DECL_SOURCE_LINE (t));
401           di->column += 6 + strlen (filename) + 8;
402         }
403       /* And any declaration can be compiler-generated.  */
404       if (DECL_ARTIFICIAL (t))
405         dump_string (di, "artificial");
406       if (TREE_CHAIN (t))
407         dump_child ("chan", TREE_CHAIN (t));
408     }
409   else if (code_class == 't')
410     {
411       /* All types have qualifiers.  */
412       int quals = CP_TYPE_QUALS (t);
413       if (quals != TYPE_UNQUALIFIED)
414         {
415           fprintf (di->stream, "qual: %c%c%c     ",
416                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
417                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
418                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
419           di->column += 14;
420         }
421
422       /* All types have associated declarations.  */
423       dump_child ("name", TYPE_NAME (t));
424
425       if (dump_children_p)
426         {
427           /* All types have a main variant.  */
428           if (TYPE_MAIN_VARIANT (t) != t)
429             dump_child ("unql", TYPE_MAIN_VARIANT (t));
430       
431           /* And sizes.  */
432           dump_child ("size", TYPE_SIZE (t));
433         }
434
435       /* All types have alignments.  */
436       dump_int (di, "algn", TYPE_ALIGN (t));
437     }
438
439   /* Now handle the various kinds of nodes.  */
440   switch (code)
441     {
442       int i;
443
444     case IDENTIFIER_NODE:
445       if (IDENTIFIER_OPNAME_P (t))
446         dump_string (di, "operator");
447       else if (IDENTIFIER_TYPENAME_P (t))
448         queue_and_dump_index (di, "tynm", TREE_TYPE (t), 0);
449       else if (t == anonymous_namespace_name)
450         dump_string (di, "unnamed");
451       else
452         {
453           dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
454           dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
455         }
456       break;
457
458     case TREE_LIST:
459       if (dump_children_p)
460         {
461           dump_child ("purp", TREE_PURPOSE (t));
462           dump_child ("valu", TREE_VALUE (t));
463           dump_child ("chan", TREE_CHAIN (t));
464         }
465       break;
466
467     case TREE_VEC:
468       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
469       if (dump_children_p)
470         for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
471           {
472             char buffer[32];
473             sprintf (buffer, "%u", i);
474             queue_and_dump_index (di, buffer, TREE_VEC_ELT (t, i), 1);
475           }
476       break;
477
478     case INTEGER_TYPE:
479     case ENUMERAL_TYPE:
480       dump_int (di, "prec", TYPE_PRECISION (t));
481       if (TREE_UNSIGNED (t))
482         dump_string (di, "unsigned");
483       if (dump_children_p)
484         {
485           dump_child ("min", TYPE_MIN_VALUE (t));
486           dump_child ("max", TYPE_MAX_VALUE (t));
487         }
488
489       if (code == ENUMERAL_TYPE && dump_children_p)
490         dump_child ("csts", TYPE_VALUES (t));
491       break;
492
493     case REAL_TYPE:
494       dump_int (di, "prec", TYPE_PRECISION (t));
495       break;
496
497     case POINTER_TYPE:
498       if (dump_children_p)
499         {
500           if (TYPE_PTRMEM_P (t))
501             {
502               dump_string (di, "ptrmem");
503               queue_and_dump_index (di, "ptd", 
504                                     TYPE_PTRMEM_POINTED_TO_TYPE (t), 1);
505               queue_and_dump_index (di, "cls", 
506                                     TYPE_PTRMEM_CLASS_TYPE (t), 1);
507             }
508           else
509             dump_child ("ptd", TREE_TYPE (t));
510         }
511       break;
512
513     case REFERENCE_TYPE:
514       if (dump_children_p)
515         dump_child ("refd", TREE_TYPE (t));
516       break;
517
518     case METHOD_TYPE:
519       if (dump_children_p)
520         dump_child ("clas", TYPE_METHOD_BASETYPE (t));
521       /* Fall through.  */
522
523     case FUNCTION_TYPE:
524       if (dump_children_p)
525         {
526           dump_child ("retn", TREE_TYPE (t));
527           dump_child ("prms", TYPE_ARG_TYPES (t));
528         }
529       break;
530
531     case ARRAY_TYPE:
532       if (dump_children_p)
533         {
534           dump_child ("elts", TREE_TYPE (t));
535           dump_child ("domn", TYPE_DOMAIN (t));
536         }
537       break;
538
539     case RECORD_TYPE:
540     case UNION_TYPE:
541       if (TYPE_PTRMEMFUNC_P (t))
542         {
543           dump_string (di, "ptrmem");
544           queue_and_dump_index (di, "ptd", 
545                                 TYPE_PTRMEM_POINTED_TO_TYPE (t), 1);
546           queue_and_dump_index (di, "cls", 
547                                 TYPE_PTRMEM_CLASS_TYPE (t), 1);
548         }
549       else
550         {
551           if (CLASSTYPE_DECLARED_CLASS (t))
552             dump_string (di, "class");
553           else if (TREE_CODE (t) == RECORD_TYPE)
554             dump_string (di, "struct");
555           else
556             dump_string (di, "union");
557
558           if (dump_children_p)
559             {
560               dump_child ("flds", TYPE_FIELDS (t));
561               dump_child ("fncs", TYPE_METHODS (t));
562               queue_and_dump_index (di, "binf", TYPE_BINFO (t), 
563                                     DUMP_CHILDREN | DUMP_BINFO);
564             }
565         }
566       break;
567
568     case CONST_DECL:
569       if (dump_children_p)
570         dump_child ("cnst", DECL_INITIAL (t));
571       break;
572
573     case VAR_DECL:
574     case PARM_DECL:
575     case FIELD_DECL:
576       if (dump_children_p)
577         {
578           dump_child ("init", DECL_INITIAL (t));
579           dump_child ("size", DECL_SIZE (t));
580         }
581       dump_int (di, "algn", DECL_ALIGN (t));
582
583       if (TREE_CODE (t) == FIELD_DECL && dump_children_p)
584         dump_child ("bpos", DECL_FIELD_BITPOS (t));
585       break;
586
587     case FUNCTION_DECL:
588       if (dump_children_p)
589         {
590           queue_and_dump_index (di, "scpe", DECL_REAL_CONTEXT (t), 0);
591           dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
592           dump_child ("args", DECL_ARGUMENTS (t));
593         }
594       if (TREE_PUBLIC (t))
595         dump_string(di, "extern");
596       else
597         dump_string (di, "static");
598       if (DECL_FUNCTION_MEMBER_P (t))
599         dump_string (di, "member");
600       if (DECL_CONSTRUCTOR_P (t))
601         dump_string (di, "constructor");
602       if (DECL_DESTRUCTOR_P (t))
603         dump_string (di, "destructor");
604       if (DECL_OVERLOADED_OPERATOR_P (t))
605         dump_string (di, "operator");
606       if (DECL_CONV_FN_P (t))
607         dump_string (di, "conversion");
608       if (dump_children_p)
609         dump_child ("body", DECL_INITIAL (t));
610       break;
611
612     case NAMESPACE_DECL:
613       /* The fake `::std' namespace does not have DECL_LANG_SPECIFIC,
614          and therefore many other macros do not work on it.  */
615       if (t == std_node)
616         break;
617       if (dump_children_p)
618         dump_child ("dcls", cp_namespace_decls (t));
619       break;
620
621     case OVERLOAD:
622       if (dump_children_p)
623         {
624           dump_child ("crnt", OVL_CURRENT (t));
625           dump_child ("chan", OVL_CHAIN (t));
626         }
627       break;
628
629     case ASM_STMT:
630       dump_stmt (di, t);
631       if (ASM_VOLATILE_P (t))
632         dump_string (di, "volatile");
633       if (dump_children_p)
634         {
635           dump_child ("strg", ASM_STRING (t));
636           dump_child ("outs", ASM_OUTPUTS (t));
637           dump_child ("ins", ASM_INPUTS (t));
638           dump_child ("clbr", ASM_CLOBBERS (t));
639         }
640       break;
641
642     case BREAK_STMT:
643     case CONTINUE_STMT:
644       dump_stmt (di, t);
645       break;
646
647     case CASE_LABEL:
648       /* Note that a case label is not like other statments; there is
649          no way to get the line-number of a case label.  */
650       if (dump_children_p)
651         {
652           dump_child ("low", CASE_LOW (t));
653           dump_child ("high", CASE_HIGH (t));
654         }
655       break;
656
657     case COMPOUND_STMT:
658       dump_stmt (di, t);
659       if (dump_children_p)
660         dump_child ("body", COMPOUND_BODY (t));
661       break;
662
663     case DECL_STMT:
664       dump_stmt (di, t);
665       if (dump_children_p)
666         dump_child ("decl", DECL_STMT_DECL (t));
667       break;
668       
669     case DO_STMT:
670       dump_stmt (di, t);
671       if (dump_children_p)
672         {
673           dump_child ("body", DO_BODY (t));
674           dump_child ("cond", DO_COND (t));
675         }
676       break;
677
678     case EXPR_STMT:
679       dump_stmt (di, t);
680       if (dump_children_p)
681         dump_child ("expr", EXPR_STMT_EXPR (t));
682       break;
683
684     case FOR_STMT:
685       dump_stmt (di, t);
686       if (dump_children_p)
687         {
688           dump_child ("init", FOR_INIT_STMT (t));
689           dump_child ("cond", FOR_COND (t));
690           dump_child ("expr", FOR_EXPR (t));
691           dump_child ("body", FOR_BODY (t));
692         }
693       break;
694
695     case GOTO_STMT:
696       dump_stmt (di, t);
697       if (dump_children_p)
698         dump_child ("dest", GOTO_DESTINATION (t));
699       break;
700
701     case IF_STMT:
702       dump_stmt (di, t);
703       if (dump_children_p)
704         {
705           dump_child ("cond", IF_COND (t));
706           dump_child ("then", THEN_CLAUSE (t));
707           dump_child ("else", ELSE_CLAUSE (t));
708         }
709       break;
710
711     case RETURN_STMT:
712       dump_stmt (di, t);
713       if (dump_children_p)
714         dump_child ("expr", RETURN_EXPR (t));
715       break;
716
717     case SWITCH_STMT:
718       dump_stmt (di, t);
719       if (dump_children_p)
720         {
721           dump_child ("cond", SWITCH_COND (t));
722           dump_child ("body", SWITCH_BODY (t));
723         }
724       break;
725
726     case TRY_BLOCK:
727       dump_stmt (di, t);
728       if (dump_children_p)
729         {
730           dump_child ("body", TRY_STMTS (t));
731           dump_child ("hdlr", TRY_HANDLERS (t));
732         }
733       break;
734
735     case WHILE_STMT:
736       dump_stmt (di, t);
737       if (dump_children_p)
738         {
739           dump_child ("cond", WHILE_COND (t));
740           dump_child ("body", WHILE_BODY (t));
741         }
742       break;
743
744     case INTEGER_CST:
745       if (TREE_INT_CST_HIGH (t))
746         dump_int (di, "high", TREE_INT_CST_HIGH (t));
747       dump_int (di, "low", TREE_INT_CST_LOW (t));
748       break;
749
750     case STRING_CST:
751       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
752       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
753       break;
754
755     case PTRMEM_CST:
756       if (dump_children_p)
757         {
758           dump_child ("clas", PTRMEM_CST_CLASS (t));
759           dump_child ("mbr", PTRMEM_CST_MEMBER (t));
760         }
761       break;
762
763     case TRUTH_NOT_EXPR:
764     case ADDR_EXPR:
765     case INDIRECT_REF:
766     case THROW_EXPR:
767       /* These nodes are unary, but do not have code class `1'.  */
768       if (dump_children_p)
769         dump_child ("op 0", TREE_OPERAND (t, 0));
770       break;
771
772     case TRUTH_ANDIF_EXPR:
773     case TRUTH_ORIF_EXPR:
774     case MODIFY_EXPR:
775     case COMPONENT_REF:
776     case COMPOUND_EXPR:
777     case COND_EXPR:
778       /* These nodes are binary, but do not have code class `2'.  */
779       if (dump_children_p)
780         {
781           dump_child ("op 0", TREE_OPERAND (t, 0));
782           dump_child ("op 1", TREE_OPERAND (t, 1));
783         }
784       break;
785
786     case CALL_EXPR:
787       if (dump_children_p)
788         {
789           dump_child ("fn", TREE_OPERAND (t, 0));
790           dump_child ("args", TREE_OPERAND (t, 1));
791         }
792       break;
793
794     case CONSTRUCTOR:
795       if (dump_children_p)
796         dump_child ("elts", TREE_OPERAND (t, 1));
797       break;
798
799     default:
800       /* There are no additional fields to print.  */
801       break;
802     }
803
804  done:
805   /* Terminate the line.  */
806   fprintf (di->stream, "\n");
807 }
808
809 /* Dump T, and all its children, on STREAM.  */
810
811 static void
812 dump_node (t, stream)
813      tree t;
814      FILE *stream;
815 {
816   struct dump_info di;
817   dump_queue_p dq;
818   dump_queue_p next_dq;
819
820   /* Initialize the dump-information structure.  */
821   di.stream = stream;
822   di.index = 0;
823   di.column = 0;
824   di.queue = 0;
825   di.queue_end = 0;
826   di.free_list = 0;
827   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0, 
828                              (splay_tree_delete_value_fn) &free);
829
830   /* Queue up the first node.  */
831   queue (&di, t, DUMP_CHILDREN);
832
833   /* Until the queue is empty, keep dumping nodes.  */
834   while (di.queue)
835     dequeue_and_dump (&di);
836
837   /* Now, clean up.  */
838   for (dq = di.free_list; dq; dq = next_dq)
839     {
840       next_dq = dq->next;
841       free (dq);
842     }
843   splay_tree_delete (di.nodes);
844 }
845
846 /* Dump T, and all its children, to FILE.  */
847
848 void
849 dump_node_to_file (t, file)
850      tree t;
851      const char *file;
852 {
853   FILE *f;
854
855   f = fopen (file, "w");
856   if (!f)
857     cp_error ("could not open `%s'", file);
858   else
859     {
860       dump_node (t, f);
861       fclose (f);
862     }
863 }