/* tree.cc: Basic Abstract Syntax Tree Implementations. */ #include #include #include "AST.h" #include "UniqueId.h" #include "code-util.h" #include "code-commonsub.h" #include "decls.h" #include "pseudocode.h" #include "streq.h" #include "utils.h" TreeNode* const TreeNode::omitted = new OmittedNode; void indent(ostream& os, int depth) { while (depth-- > 0) os << ' ' << ' '; } static void append( string &texts, Common::Modifiers &flags, int mask, const char text[] ) { if ((flags & mask) == mask) { flags = (Common::Modifiers) (flags & ~mask); if (!texts.empty()) texts += ' '; texts += text; } } string stringifyModifiers (Common::Modifiers flags) { string result; append(result, flags, Common::Public, "public"); append(result, flags, Common::Private, "private"); append(result, flags, Common::Protected, "protected"); append(result, flags, Common::Static, "static"); append(result, flags, Common::Final, "final"); append(result, flags, Common::Synchronized, "synchronized"); append(result, flags, Common::Volatile, "volatile"); append(result, flags, Common::Transient, "transient"); append(result, flags, Common::Native, "native"); append(result, flags, Common::Interface, "interface"); append(result, flags, Common::Abstract, "abstract"); append(result, flags, Common::Single, "single"); append(result, flags, Common::Local | Common::LocalInferred, "(local)"); append(result, flags, Common::Local, "local"); append(result, flags, Common::Immutable, "immutable"); append(result, flags, Common::Sglobal, "single"); append(result, flags, Common::Inline, "inline"); append(result, flags, Common::CompilerGenerated, "(compiler-generated)"); append(result, flags, Common::NonsharedQ | Common::SharingInferred, "(nonshared)"); append(result, flags, Common::PolysharedQ | Common::SharingInferred, "(polyshared)"); append(result, flags, Common::NonsharedQ, "nonshared"); append(result, flags, Common::PolysharedQ, "polyshared"); append(result, flags, Common::Strictfp, "strictfp"); append(result, flags, Common::MemberType, "(MemberType)"); append(result, flags, Common::LocalClass, "(LocalClass)"); append(result, flags, Common::AnonymousClass, "(AnonymousClass)"); assert( !flags ); return result; } /** Print a representation of T on OS, indenting each line after the first by INDENT spaces. Also handles T == NULL. */ void printNode (const TreeNode* t, ostream& os, int indent) { if (t == NULL) { os << "*NULL*"; Error(NoSourcePosition) << "Internal error: NULL child link encountered in the AST" << endl; } else t->print (os, indent); } static int nextTreeUID = 1; TreeNode::TreeNode(SourcePosn where, TreeNode **children) : where( where ), _parent(NULL), children( children ), _uid (nextTreeUID), _uselist(NULL), _deflist(NULL) { nextTreeUID += 1; } TreeNode::TreeNode(const TreeNode& t) { *this = t; _uid = nextTreeUID; nextTreeUID += 1; } /* Print a representation of *this on OS, indenting each line */ /* after the first by INDENT spaces. */ void TreeNode::print (ostream& os, unsigned depth) const { indent(os, depth); os << '(' << oper_name(); os << '<'; if(position().file) os << *position().file; else os << "unknown"; os << ' ' << position().posnToLineNumber () << "> @ " << this; for (int i = 0; i < arity(); i += 1) { os << '\n'; printNode (children[i], os, depth + 1); } print_attrs(os, depth); os << ')'; } /* Print a the attributes of *this on OS, indenting each line */ /* after the first by INDENT spaces. */ void TreeNode::print_attrs (ostream& os, unsigned depth) const { } bool TreeNode::compare(const TreeNode *t) const { cerr << "Internal error: compare() undefined on:\n"; print(cerr, 4); cerr << '\n'; undefined("compare"); return false; } /* When true, indicates an optional node that is absent (that is, */ /* that the node comes from the static constant omitted, defined */ /* below). */ bool TreeNode::absent() const { return false; } /* The printed name of the operator for *this. */ const char* TreeNode::oper_name() const { return "-*-"; } /* The number of children this node possesses. */ int TreeNode::arity() const { return 0; } /* Report a fatal error and exit. */ void TreeNode::fatal (const string& msg) const { cout.flush(); cerr << position() << " fatal error: " << msg << " in a " << oper_name() << endl << "Offending node: " << pseudocode(this) << endl << "parent of offending node: " << pseudocode(parent()) << endl << endl; abort(); exit(1); } /* Report that name is undefined and exit. */ void TreeNode::undefined (const string& name) const { fatal(name + " undefined"); } /* Report that a feature is not yet implemented and exit. */ void TreeNode::unimplemented( const string& feature ) const { cerr << position() << "feature not yet implemented: " << feature << endl; exit(1); } /* Set line number from children, if not determined by P. */ void TreeNode::setWhere (SourcePosn p) { int i; where = p; i = 0; while (where.unknown() && i < arity()) { if (children[i]) where = children[i]->position(); i += 1; } } /* An iterator over all children of *THIS. */ TreeNode::ChildIter TreeNode::allChildren() { return ChildIter (children, arity()); } TreeNode::ConstChildIter TreeNode::allChildren() const { return ConstChildIter (children, arity()); } /* An iterator over all children of *THIS, assuming they are TypeNodes. */ TreeNode::TypeIter TreeNode::allTypes() { return TypeIter ((TypeNode **)children, arity()); } TreeNode::ConstTypeIter TreeNode::allTypes() const { return ConstTypeIter ((TypeNode **)children, arity()); } const string TreeNode::emitExpression( CodeContext & ) { undefined( "emitExpression" ); return ""; } bool TreeNode::isLocalLvalue() { undefined( "isLocalLvalue" ); return false; } bool TreeNode::isSimpleLvalue() { return false; } const string TreeNode::simpleVar( CodeContext & ) { undefined( "simpleVar" ); return ""; } const string TreeNode::getLvalue( CodeContext & ) { undefined( "getLvalue" ); return ""; } const string TreeNode::declareTemporary( LocalVars & ) { undefined( "declareTemporary" ); return ""; } void TreeNode::emitCatchTable( ostream & ) const { undefined("emitCatchTable"); } const string TreeNode::emitUse( LocalVars &context, const ObjectNode &subject ) const { return parent()->emitUse( context, subject ); } const string TreeNode::emitMethodCall( CodeContext &, TreeListNode & ) { undefined( "emitMethodCall" ); return ""; } bool TreeNode::selectedForCodeGen(bool) const { return true; } /* TreeListNode */ size_t list_recovery = 0; void TreeListNode::initialize( llist *childList ) { if (childList) { _arity = childList->size(); children = new PASS_RETADR TreeNode * [ _arity ]; for (int slot = 0; slot < (int)_arity; ++slot) { TreeNode * const adoptee = childList->front(); childList = childList->free(); child( slot, adoptee ); if (where.unknown()) where = adoptee->position(); } assert( !childList ); list_recovery += _arity; } else { children = 0; _arity = 0; } } const char* TreeListNode::oper_name() const { return "*list*"; } void TreeListNode::print (ostream& os, unsigned depth) const { indent(os, depth); os << '('; foriter (p, allChildren(), ConstChildIter) { os << '\n'; printNode (*p, os, depth + 1); } os << ')'; } bool apparentlyIdenticalChildren(const TreeNode *u, const TreeNode *t) { if (!streq(u->oper_name(), t->oper_name())) return false; if (u->arity() != t->arity()) return false; for (int i = u->arity(); --i >= 0; ) if (!COMPARE(u->child(i), t->child(i))) return false; return true; } bool TreeListNode::compare(const TreeNode *t) const { return apparentlyIdenticalChildren(this, t); } int TreeListNode::arity() const { return _arity; } template class llist; llist *appendTreeList(TreeListNode *l1, llist *l2) { for (int i = l1->arity() - 1; i >= 0; i--) l2 = cons(l1->child(i), l2); return l2; } llist *addToFront(TreeNode *l1, TreeListNode *l2) { if (l2->arity() <= 0) { return cons(l1); } else { llist *lst = cons(l2->child(l2->arity() - 1)); for (int i = l2->arity() - 2; i >= 0; i--) { lst = cons(l2->child(i), lst); } return cons(l1, lst); } } TreeListNode *remove(TreeListNode *lst, TreeNode *elem) { llist *tmp = NULL; for (int i = lst->arity() - 1; i >= 0; i--) if (elem != lst->child(i)) tmp = cons(lst->child(i), tmp); return new TreeListNode(tmp, lst->position()); } // OmittedNode void OmittedNode::print (ostream& os, unsigned depth) const { indent(os, depth); os << "-*-"; } TypeNode* OmittedNode::type() { return theVoidType; } const string OmittedNode::emitExpression( CodeContext & ) { return "void"; } // The errorName method /* Return a string representing this node suitable for printing */ /* in an error message */ string TreeNode::errorName() const { return "(unnamed)"; // Shouldn't be called, but fatal() seems a bad move } /* Debugging functions */ /* Print of AST rooted at T. */ void dbg_ast_print (TreeNode* t) { if (t == NULL) cout << "*null*"; else t->print (cout, 0); cout << endl; } /* Print of pseudocode for AST rooted at T. */ void dbg_pseudoprint (TreeNode* t) { if (t == NULL) cout << "*null*"; else t->pseudoprint (cout, 0); cout << endl; } /* Short description of node at T, no subtrees. */ void dbg_ast_id (TreeNode* t) { if (t == NULL) cout << "*null*" << endl; else cout << "Node #" << t->uid () << "@" << t << " (" << t->oper_name () << " at " << t->position () << ")" << endl; }