// // See copyright.h for copyright notice and limitation of liability // and disclaimer of warranty provisions. // #include "copyright.h" #include "cool.h" #include "tree.h" #include "cool-tree.h" #include "utilities.h" // defined in stringtab.cc void dump_Symbol(ostream& stream, int padding, Symbol b); // defined in cool.h void dump_Boolean(ostream& stream, int padding, Boolean b); ////////////////////////////////////////////////////////////////// // // dumptype.cc // // dumptype defines a simple recursive traversal of the abstract // syntax tree (AST) that prints each node and any associated // type information. Use dump_with_types to inspect the results of // type inference. // // dump_with_types takes two argumenmts: // an output stream // an indentation "n", the number of blanks to insert at the beginning of // a new line. // // dump_with_types is just a simple pretty printer, formatting the output // to show the AST relationships between nodes and their types. // dump_type is a virtual function, with a separate implementation for // each kind of AST node. Using virtual functions is an easy way to // implement recursive tree traversals in C++; each kind of tree node // has a virtual function that "knows" how to perform the part of // the traversal for that one node. It may help to know the inheritance hierarchy // of the classes that define the structure of the Cool AST. In the // list below, the outer classes are the Phyla which group together // related kinds of abstract tree nodes (e.g., the two kinds of Features // and the many different kinds of Expression). The inner, indented classes // inherit from the nearest Phyla class; these are the concrete classes that // appear in the AST. // // Program_class // program_class // // Class__class // class_ // // Feature_class // method // attr // // Formal_class // formal // // Case_class // branch_class // // Expression_class // assign // static_dispatch // dispatch // cond // loop // typcase // block // let // plus // sub // mul // divide // neg // lt // eq // leq // comp // int_const // bool_const // string_const // new_ // isvoid // no_expr // object // // All of the Phyla inherit from the tree_node class, which has a member // called type. The type member holds the type of the AST node. // // Some AST nodes have lists of other tree nodes as components. Lists in the // AST are built using the class list_node defined in tree.h. The list // classes in the Cool AST are: // // Classes a list of Class_ // Features a list of Feature // Expressions a list of Expression // Cases a list of Case // // // dump_type prints the type of an Expression on the output stream, // after indenting the correct number of spaces. A check is made to // see if no type is assigned to the node. // // Note that the "type" member referred to here is inherited from tree_node // by all subclasses of Expression_class. Note also that dump_type is // defined for the Phylum Expression here, and is therefore inherited by // every distinct subclass of Expression. // void Expression_class::dump_type(ostream& stream, int n) { if (type) { stream << pad(n) << ": " << type << endl; } else { stream << pad(n) << ": _no_type" << endl; } } void dump_line(ostream& stream, int n, tree_node *t) { stream << pad(n) << "#" << t->get_line_number() << "\n"; } // // program_class prints "program" and then each of the // component classes of the program, one at a time, at a // greater indentation. The recursive invocation on // "classes->nth(i)->dump_with_types(...)" shows how useful // and compact virtual functions are for this kind of computation. // // Note the use of the iterator to cycle through all of the // classes. The methods first, more, next, and nth on AST lists // are defined in tree.h. // void program_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_program\n"; for(int i = classes->first(); classes->more(i); i = classes->next(i)) classes->nth(i)->dump_with_types(stream, n+2); } // // Prints the components of a class, including all of the features. // Note that printing the Features is another use of an iterator. // void class__class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_class\n"; dump_Symbol(stream, n+2, name); dump_Symbol(stream, n+2, parent); stream << pad(n+2) << "\""; print_escaped_string(stream, filename->get_string()); stream << "\"\n" << pad(n+2) << "(\n"; for(int i = features->first(); features->more(i); i = features->next(i)) features->nth(i)->dump_with_types(stream, n+2); stream << pad(n+2) << ")\n"; } // // dump_with_types for method_class first prints that this is a method, // then prints the method name followed by the formal parameters // (another use of an iterator, this time access all of the list members // of type Formal), the return type, and finally calls dump_type recursively // on the method body. void method_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_method\n"; dump_Symbol(stream, n+2, name); for(int i = formals->first(); formals->more(i); i = formals->next(i)) formals->nth(i)->dump_with_types(stream, n+2); dump_Symbol(stream, n+2, return_type); expr->dump_with_types(stream, n+2); } // // attr_class::dump_with_types prints the attribute name, type declaration, // and any initialization expression at the appropriate offset. // void attr_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_attr\n"; dump_Symbol(stream, n+2, name); dump_Symbol(stream, n+2, type_decl); init->dump_with_types(stream, n+2); } // // formal_class::dump_with_types dumps the name and type declaration // of a formal parameter. // void formal_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_formal\n"; dump_Symbol(stream, n+2, name); dump_Symbol(stream, n+2, type_decl); } // // branch_class::dump_with_types dumps the name, type declaration, // and body of any case branch. // void branch_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_branch\n"; dump_Symbol(stream, n+2, name); dump_Symbol(stream, n+2, type_decl); expr->dump_with_types(stream, n+2); } // // assign_class::dump_with_types prints "assign" and then (indented) // the variable being assigned, the expression, and finally the type // of the result. Note the call to dump_type (see above) at the // end of the method. // void assign_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_assign\n"; dump_Symbol(stream, n+2, name); expr->dump_with_types(stream, n+2); dump_type(stream,n); } // // static_dispatch_class::dump_with_types prints the expression, // static dispatch class, function name, and actual arguments // of any static dispatch. // void static_dispatch_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_static_dispatch\n"; expr->dump_with_types(stream, n+2); dump_Symbol(stream, n+2, type_name); dump_Symbol(stream, n+2, name); stream << pad(n+2) << "(\n"; for(int i = actual->first(); actual->more(i); i = actual->next(i)) actual->nth(i)->dump_with_types(stream, n+2); stream << pad(n+2) << ")\n"; dump_type(stream,n); } // // dispatch_class::dump_with_types is similar to // static_dispatch_class::dump_with_types // void dispatch_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_dispatch\n"; expr->dump_with_types(stream, n+2); dump_Symbol(stream, n+2, name); stream << pad(n+2) << "(\n"; for(int i = actual->first(); actual->more(i); i = actual->next(i)) actual->nth(i)->dump_with_types(stream, n+2); stream << pad(n+2) << ")\n"; dump_type(stream,n); } // // cond_class::dump_with_types dumps each of the three expressions // in the conditional and then the type of the entire expression. // void cond_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_cond\n"; pred->dump_with_types(stream, n+2); then_exp->dump_with_types(stream, n+2); else_exp->dump_with_types(stream, n+2); dump_type(stream,n); } // // loop_class::dump_with_types dumps the predicate and then the // body of the loop, and finally the type of the entire expression. // void loop_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_loop\n"; pred->dump_with_types(stream, n+2); body->dump_with_types(stream, n+2); dump_type(stream,n); } // // typcase_class::dump_with_types dumps each branch of the // the Case_ one at a time. The type of the entire expression // is dumped at the end. // void typcase_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_typcase\n"; expr->dump_with_types(stream, n+2); for(int i = cases->first(); cases->more(i); i = cases->next(i)) cases->nth(i)->dump_with_types(stream, n+2); dump_type(stream,n); } // // The rest of the cases for Expression are very straightforward // and introduce nothing that isn't already in the code discussed // above. // void block_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_block\n"; for(int i = body->first(); body->more(i); i = body->next(i)) body->nth(i)->dump_with_types(stream, n+2); dump_type(stream,n); } void let_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_let\n"; dump_Symbol(stream, n+2, identifier); dump_Symbol(stream, n+2, type_decl); init->dump_with_types(stream, n+2); body->dump_with_types(stream, n+2); dump_type(stream,n); } void plus_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_plus\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void sub_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_sub\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void mul_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_mul\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void divide_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_divide\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void neg_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_neg\n"; e1->dump_with_types(stream, n+2); dump_type(stream,n); } void lt_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_lt\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void eq_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_eq\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void leq_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_leq\n"; e1->dump_with_types(stream, n+2); e2->dump_with_types(stream, n+2); dump_type(stream,n); } void comp_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_comp\n"; e1->dump_with_types(stream, n+2); dump_type(stream,n); } void int_const_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_int\n"; dump_Symbol(stream, n+2, token); dump_type(stream,n); } void bool_const_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_bool\n"; dump_Boolean(stream, n+2, val); dump_type(stream,n); } void string_const_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_string\n"; stream << pad(n+2) << "\""; print_escaped_string(stream,token->get_string()); stream << "\"\n"; dump_type(stream,n); } void new__class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_new\n"; dump_Symbol(stream, n+2, type_name); dump_type(stream,n); } void isvoid_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_isvoid\n"; e1->dump_with_types(stream, n+2); dump_type(stream,n); } void no_expr_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_no_expr\n"; dump_type(stream,n); } void object_class::dump_with_types(ostream& stream, int n) { dump_line(stream,n,this); stream << pad(n) << "_object\n"; dump_Symbol(stream, n+2, name); dump_type(stream,n); }