INTERFACE: #include #include "ptree_nodes.h" #include "type_rep.h" class Symbol; class Variable_symbol; class Function_signature; /** Annotation for an expression. */ class Annotation { Type type; Symbol* symbol; int flags; public: Type get_type() const { return type; } Symbol* get_symbol() const { return symbol; } enum Flag { af_DirectCall // suppress virtual function call for this call }; }; template class Annotated : public T, public Annotation { public: template Annotated(Type type, Symbol* sym, U arg, Ptree* a, Ptree* b) : T(arg, a, b), Annotation(type, sym) { } }; class Annotated_funcall_maker { Ptree* function; Type result_type; Ptree* tree; }; IMPLEMENTATION: #include #include #include #include #include "symbol_table.h" #include "variable.h" #include "function.h" #include "except.h" #include "unmangle.h" using namespace Opencxx; PUBLIC Annotation::Annotation(Type type, Symbol* sym) : type(type), symbol(sym) { } PUBLIC virtual Annotation::~Annotation() { } PUBLIC inline void Annotation::set_symbol(Symbol* symbol) { this->symbol = symbol; } PUBLIC inline void Annotation::set_type(Type type) { this->type = type; } PUBLIC inline void Annotation::add_flag(Flag f) { flags |= 1 << f; } PUBLIC inline bool Annotation::has_flag(Flag f) { return flags & (1 << f); } PUBLIC inline void Annotation::remove_flag(Flag f) { flags &= ~(1 << f); } PUBLIC template Annotated::Annotated(Type type, Symbol* sym) : T(), Annotation(type, sym) { } PUBLIC template Annotated::Annotated(Type type, Symbol* sym, T& src) : T(src), // hehe Annotation(type, sym) { } PUBLIC template Annotated::Annotated(Type type, Symbol* sym, Ptree* a, Ptree* b) : T(a, b), Annotation(type, sym) { } PUBLIC template Annotated::Annotated(Type type, Symbol* sym, Ptree* a, Ptree* b, Ptree* c) : T(a, b, c), Annotation(type, sym) { } /**************************** Accessors **************************/ Leaf* make_static_leaf(const char* txt) { return new Leaf(const_cast(txt), std::strlen(txt)); } Leaf* make_dup_leaf(const char* txt) { char* ntxt = new char[std::strlen(txt)+1]; std::strcpy(ntxt, txt); Token tmp_tok = { ntxt, std::strlen(txt), ntName }; return new Leaf(tmp_tok); } Leaf* make_dup_leaf(std::string txt) { return make_dup_leaf(txt.c_str()); } Annotated* make_this(Type type) { Token tmp_tok = { "this", 4, THIS }; LeafThis tmp_leaf(tmp_tok); return new Annotated(type.make_pointer_type().with_qualifier(Type::q_Const), 0, tmp_leaf); } Annotated* make_name(const char* txt, Type type, Symbol* sym) { char* ntxt = new char[std::strlen(txt)+1]; std::strcpy(ntxt, txt); Token tmp_tok = { ntxt, std::strlen(txt), ntName }; LeafName tmp_leaf(tmp_tok); return new Annotated(type, sym, tmp_leaf); } Annotated* make_name(std::string str, Type type, Symbol* sym) { return make_name(str.c_str(), type, sym); } Annotated* make_name(Function_signature* fsig) { std::string s = fsig->get_name(); if (!s.length()) s = fsig->get_function()->get_name(); return make_name(s.c_str(), fsig->get_call_type(), fsig); } Annotated* make_name(Variable_symbol* vsym) { return make_name(vsym->get_name().c_str(), vsym->get_type(), vsym); } Annotated* make_cast_expr_unchecked(Ptree* expr, const Type& target_type) { /* PtreeFstyleCastExpr: [type ( [expr] )] */ return new Annotated(target_type, 0, (char*) "", /* encoded type */ make_name(target_type.get_encoded_type().c_str(), target_type, 0), Ptree::List(make_static_leaf("("), expr, make_static_leaf(")"))); } /** Create a function-style cast. This one's used for built-in types. */ Annotated* make_cast_expr(Ptree* expr, Type target_type) { assert(target_type.is_valid()); assert(!target_type.is_class_type()); return make_cast_expr_unchecked(expr, target_type); } /** Create a derived-to-base cast. Right now, this generates the same tree as make_cast_expr. */ Annotated* make_derived_to_base_cast(Ptree* expr, Type target_type) { assert(target_type.is_valid()); assert(target_type.is_class_type()); return make_cast_expr_unchecked(expr, target_type); } /** Create a comma expression. These are handled specially: (a, (b, c)) is converted into ((a, b), c) so that the RHS of a comma expression never is a comma expression itself. */ Annotated* make_comma_expr(Ptree* lhs, Ptree* rhs) { Annotation* lanno = dynamic_cast(lhs); Annotation* ranno = dynamic_cast(rhs); assert(lanno); assert(ranno); if (PtreeCommaExpr* cx = dynamic_cast(rhs)) { lhs = make_comma_expr(lhs, rhs->First()); rhs = rhs->Third(); ranno = dynamic_cast(rhs); assert(ranno); } return new Annotated(ranno->get_type(), 0, lhs, Ptree::List(make_static_leaf(","), rhs)); } Annotated* make_declaration(Variable_symbol* vsym) { /* format of a variable declaration is: "a b;" => Declaration@[null TYPE [Declarator@[NAME]] ;] "a b(args);" => Declaration@[null TYPE [Declarator@[NAME [( args )]]] ;] "a b = x;" => Declaration@[null TYPE [Declarator@[NAME = EXPR]]] We don't generate initializers; those can be snarfed from the actual variable symbol if needed. */ Encoding tmp_enc; PtreeDeclarator* decl = new PtreeDeclarator(Ptree::List(make_dup_leaf(vsym->get_name())), tmp_enc); return new Annotated(vsym->get_type(), vsym, 0 /* storage class etc. */, Ptree::List(make_dup_leaf(vsym->get_type().get_encoded_type()), decl, make_static_leaf(";"))); } /** Fill in result of overload resolution. Comma expressions must be handled specially. */ void fill_in_overload_annotation(Ptree* tree, Symbol* sym, Type t) { Annotation* anno = dynamic_cast(tree); assert(anno); anno->set_type(t); if (PtreeCommaExpr* cx = dynamic_cast(tree)) fill_in_overload_annotation(cx->Third(), sym, t); else anno->set_symbol(sym); } /*********************** Annotated_funcall_maker *******************************/ PUBLIC Annotated_funcall_maker::Annotated_funcall_maker(Ptree* function, Type result_type) : function(function), result_type(result_type), tree(0) { } PUBLIC Annotated_funcall_maker::~Annotated_funcall_maker() { } PUBLIC void Annotated_funcall_maker::add_arg(Ptree* arg) { if (!tree) { tree = new NonLeaf(arg, 0); } else { tree = Ptree::Snoc(tree, make_static_leaf(",")); tree = Ptree::Snoc(tree, arg); } } PUBLIC Ptree* Annotated_funcall_maker::make_funcall() { /* Function call leaf: [function ( null )] [function ( [a , b , ...] ) */ if (PtreeCommaExpr* cx = dynamic_cast(function)) { compile_warning("calling a comma expression", cx); return make_comma_expr(function->First(), new Annotated(result_type, 0, function->Third(), Ptree::List(make_static_leaf("("), tree, make_static_leaf(")")))); } else { return new Annotated(result_type, 0, function, Ptree::List(make_static_leaf("("), tree, make_static_leaf(")"))); } } /* Handy function */ Ptree* make_unary_funcall(Ptree* function, Type result, Ptree* arg) { Annotated_funcall_maker afm(function, result); afm.add_arg(arg); return afm.make_funcall(); } /* Just a hack to save typing :-) */ #define COLOR_(c) #c #define COLOR(c) (colors ? "\033[" COLOR_(c) "m" : "") #define cBlack 30 #define cRed 31 #define cGreen 32 #define cYellow 33 #define cBlue 34 #define cMagenta 35 #define cCyan 36 #define cWhite 37 /* meta information -> black names -> red types -> green node content -> blue */ void print_annotated_tree(std::ostream& out, std::string indent, Ptree* tree, bool colors) { if (!tree) { out << indent << "null"; return; } Annotation* an = dynamic_cast(tree); out << indent; if (an) { out << "["; if (Symbol* sym = an->get_symbol()) { std::string n = sym->get_name(); if (n.length()) out << COLOR(cRed) << n << COLOR(0); else out << "unnamed"; } else { out << "no symbol"; } Type t = an->get_type(); if (t.is_valid()) { out << ", " << COLOR(cGreen) << t.make_pointer_type().get_encoded_type().substr(1) << COLOR(0); } if (an->has_flag(Annotation::af_DirectCall)) out << ", direct"; out << "] "; } if (tree->IsLeaf()) { out << COLOR(cBlue) << tree->ToString() << COLOR(0); if (Symbol_table::has_dump_flag('a')) out << " @" << (void*)tree; } else { out << unmangle(typeid(*tree).name()); if (Symbol_table::has_dump_flag('a')) out << " @" << (void*)tree; while (tree) { out << "\n"; print_annotated_tree(out, indent + " ", tree->Car(), colors); tree = tree->Cdr(); } } }