#include "cmm.h" #include "parser2.h" #include "../utils/exceptionstream.h" #include "../utils/debug.h" #include #include namespace { const parser::identifier_t* GetIdentifier( parser::lexer_t& lexer, const char* name=NULL) { debug_TRACE; const parser::identifier_t* id = dynamic_cast< const parser::identifier_t*>( lexer.PeekNext()); if ( !id) return NULL; if ( name) { if ( (int) strlen( name) != id->end-id->begin || strncmp( name, id->begin, strlen( name))) return NULL; } lexer.GetNext(); return id; } int GetInt( parser::lexer_t& lexer) { debug_TRACE; const parser::number_t* n = parser::TryPeek< const parser::number_t>( lexer); if ( !n) throw parser::error_t( lexer, "Expecting number"); lexer.GetNext(); int x; if ( 1 != sscanf( n->begin, "%i", &x)) throw std::runtime_error( "error_t parsing number"); return x; } } namespace cmm { int Comp( const cmm::ThirdPassInfo::VirtFn::Impl::Param& a, const cmm::ThirdPassInfo::VirtFn::Impl::Param& b) { debug_TRACE; for ( unsigned int i=0; ; ++i) { if ( i==a.classnames.size() && i==b.classnames.size()) return 0; // identical if ( i==a.classnames.size()) return -1; // b more derived than a. if ( i==b.classnames.size()) return 1; // a more derived than b. if ( *a.classnames[i] != *b.classnames[i]) return 0; // a and b are unrelated (although they share a base class). } throw std::logic_error( "Oops..."); } int CompareImplPtrs0( const cmm::ThirdPassInfo::VirtFn::Impl* const & a, const cmm::ThirdPassInfo::VirtFn::Impl* const & b) { debug_TRACE; if ( a->params.size() != b->params.size()) throw std::logic_error( "Impls have different number of virt params - should never happen"); int compare = 0; for ( unsigned int i=0; iparams.size(); ++i) { int c = Comp( *a->params[i], *b->params[i]); if ( 0) ; else if ( c!=0 && compare!=0 && c!=compare) return 0; else if ( c!=0 && compare==0) compare = c; else if ( c==0) {} } return compare; } bool CompareImplPtrs( const cmm::ThirdPassInfo::VirtFn::Impl* const & a, const cmm::ThirdPassInfo::VirtFn::Impl* const & b) { debug_TRACE; return ( CompareImplPtrs0( a, b) > 0) ? true : false; // Sorts in decreasing specialisation } } cmm::ThirdPassInfo::ThirdPassInfo( const cmm::ThirdPassInfo::Extra& extra0) : extra( extra0), virtfns() { } cmm::ThirdPassInfo::Extra::Extra() : mapinclude( "#include \n"), maptype( "std::map"), profileinclude( ""), profiletype( ""), arrayinclude( "#include "), arraytype( "std::vector"), no_exceptions_in_generated_code( false) { } void cmm::ThirdPassInfo::AddFns( std::istream& in) { // read complete input .cmmi file into buffer: std::string* buffer = new std::string; for(;;) { char c = static_cast< char>( in.get()); if ( in.eof()) break; *buffer += c; } parser::lexer_t lexer( "Unknown file", buffer->c_str()); for(;;) { const parser::identifier_t* id = GetIdentifier( lexer, "virtualfunction"); if ( !id) break; parser::string_t* filename = parser::Get< parser::string_t>( lexer); parser::context_t context; parser::declarator_names_t* declnames = dynamic_cast< parser::declarator_names_t*>( get_top_level_node( lexer, context)); if ( !declnames || declnames->items.size()!=1) throw parser::error_t( lexer, "Expecting fn prototype"); parser::declarator_terminator_t* declterm = declnames->items.front(); parser::function_t* fn = declterm->declarator->is_simple_function(); if ( !fn) throw parser::error_t( lexer, "Expecting fn prototype"); if (fn->parameters->num_virtparams == 0) throw parser::error_t( lexer, "Virt fn has no virt params"); //std::cerr << "Read virtual function from .cmmi file: " << *virtfn->name() << "\n"; // look for this virtfn in existing virtual functions. unsigned int i; for ( i=0; ivirtfns.size(); ++i) { // operator == ignores names - just compares types - but we are // interested in fn names too, so we compare them explicitly if ( *declterm->declarator->is_name()==*virtfns[i]->virtfn->items.back()->declarator->is_name() && *declnames == *virtfns[i]->virtfn) { /*std::cerr << "Virt fn "; std::cerr << *declnames; std::cerr << " already seen\n";*/ break; } } if ( i==this->virtfns.size()) { //debug << "Adding virtual fn: " << *declnames << "\n"; this->virtfns.push_back( new VirtFn); this->virtfns[i]->virtfn = declnames; this->virtfns[i]->filename = filename; } // i is index of the virtual function in our list of virtual functions. for(;;) { if ( !GetIdentifier( lexer, "implementation")) break; VirtFn::Impl* impl = new VirtFn::Impl; this->virtfns[i]->impls.push_back( impl); const parser::string_t* impl_filename = parser::TryPeek< parser::string_t>( lexer); if ( !impl_filename) throw parser::error_t( lexer, "Expected filename"); if ( impl_filename->end-filename->begin < 2) throw parser::error_t( lexer, "Filename string too short"); lexer.GetNext(); impl->filename = impl_filename->GetContents(); //std::cerr << "filename is `" << impl->filename << "'\n"; unsigned int num_virtparams = GetInt( lexer); if ( num_virtparams != fn->parameters->num_virtparams) throw parser::error_t( lexer, "Impl has wrong number of virtual params"); //std::cerr << "Num virt params = " << num_virtparams << "\n"; for ( unsigned int param_num=0; param_num < num_virtparams; ++param_num) { VirtFn::Impl::Param* param = new VirtFn::Impl::Param; impl->params.push_back( param); unsigned int derivedness = GetInt( lexer); //std::cerr << "number_t of class names in this derivation = " << derivedness << "\n"; for ( unsigned int d=0; dclassnames.push_back( name); } } //std::cerr << "Just about to read implmatch prototype. Next node is " << *lexer.PeekNext() << "\n"; parser::context_t implmatch_context; parser::declarator_names_t* implmatch = dynamic_cast< parser::declarator_names_t*>( parser::get_top_level_node( lexer, implmatch_context)); parser::declarator_names_t* implcall = dynamic_cast< parser::declarator_names_t*>( parser::get_top_level_node( lexer, implmatch_context)); if ( !implcall || !implmatch || implcall->items.size()!=1 || implmatch->items.size()!=1) throw exception_stream() << "CMM Info file is corrupt: Expected implmatch amd implecall functions but got " << *impl->implmatch << " " << *impl->implcall; impl->implcall = implcall; impl->implmatch = implmatch; if ( !impl->implmatch || !impl->implcall) throw exception_stream() << "CMM Info file is corrupt: Expected implmatch amd implecall functions but got " << *impl->implmatch << " " << *impl->implcall; } } if ( !parser::TryPeek< parser::endoffile_t>( lexer)) throw parser::error_t( lexer, "Unrecognised text"); //std::cerr << "There are " << this->virtfns.size() << " virtual functions\n"; } namespace { void Output0( parser::outstream_t& out, const cmm::ThirdPassInfo::VirtFn::Impl& impl) { for ( cmm::ThirdPassInfo::VirtFn::Impl::params_t::const_iterator param=impl.params.begin(); param!=impl.params.end(); ++param) { for ( cmm::ThirdPassInfo::VirtFn::Impl::Param::classnames_t::const_iterator classname=(*param)->classnames.begin(); classname!=(*param)->classnames.end(); ++classname) { (*classname)->output_compact( out); out.out << " "; } out.out << ", "; } } void Output0( parser::outstream_t& out, const cmm::ThirdPassInfo::VirtFn& vf) { out.out << "Virtual fn "; out << *vf.virtfn; for ( cmm::ThirdPassInfo::VirtFn::impls_t::const_iterator impl=vf.impls.begin(); impl!=vf.impls.end(); ++impl) { out.out << " Implementation: ( "; Output0( out, **impl); out.out << ")\n"; } } void Output0( parser::outstream_t& out, const cmm::ThirdPassInfo& tpi) { for ( cmm::ThirdPassInfo::virtfns_t::const_iterator virtfn=tpi.virtfns.begin(); virtfn!=tpi.virtfns.end(); ++virtfn) { Output0( out, **virtfn); } } } void cmm::ThirdPassInfo::output( std::ostream& out0) const { parser::outstream_t out( out0); out.remove_virtual_from_functionparams = true; Output0( out, *this); for ( unsigned int i=0; iextra)->output( out); } } parser::declarator_names_t* cmm::MakeLookupFn( cmm::ThirdPassInfo::VirtFn* virtfn, const cmm::ThirdPassInfo& thirdpassinfo) { //debug << "cmm::MakeLookupFn called\n"; if ( virtfn->impls.size()==0) throw exception_stream() << "Virtual function `" << *virtfn->virtfn << "' has no implementations"; std::sort( virtfn->impls.begin(), virtfn->impls.end(), CompareImplPtrs); /* Get the type of the match functions - all implementations' match functions will be this type. */ parser::declarator_terminator_t* matchfn = virtfn->impls[0]->implmatch->items.back(); assert( matchfn); //debug << *virtfn->impls[0]->implmatch << "\n"; //debug << *virtfn->impls[0]->implcall << "\n"; { /*outstream_t out( std::cerr); out.out << "matchfn is: "; matchfn->output_complete( out);*/ } /* The dispatch function that we create: */ parser::declarator_names_t* declnames = new parser::declarator_names_t; parser::declarator_terminator_t* declterm = new parser::declarator_terminator_t; declnames->items.push_back( declterm); parser::declarator_name_t* declname = new parser::declarator_name_t(); declterm->declarator = declname; declname->name = new parser::name_t( *virtfn->virtfn->items.front()->declarator->is_name()->name); parser::add_suffix( declname->name, "_cmm_lookup"); parser::function_t* fn = new parser::function_t; declname->subtype = fn; parser::pointer_t* ptr = new parser::pointer_t; fn->subtype = ptr; ptr->star = new parser::keyword_STAR( "*"); parser::bracket_declarator_t* bracketdecl = new parser::bracket_declarator_t; ptr->subtype = bracketdecl; bracketdecl->open = new parser::keyword_OPENROUND( "("); bracketdecl->close = new parser::keyword_CLOSEROUND( ")"); bracketdecl->subtype = virtfn->virtfn->items.front()->declarator->subtype; //debug << "fn subtype is: " << *fn->subtype << "\n"; declnames->declleft = virtfn->virtfn->declleft; //debug << "declleft=" << typeid( *declnames->declleft).name() << "\n" << *declnames->declleft << ", " << declnames->declleft->name << ": " << *declnames->declleft->name << "\n"; assert( matchfn->declarator->is_simple_function()); fn->parameters = matchfn->declarator->is_simple_function()->parameters; // reuse these parameters. ensure_parameter_names( fn->parameters); //debug << "declnames is: " << *declnames << "\n"; std::stringstream internal_body; parser::outstream_t internal_body2( internal_body); internal_body2.remove_virtual_from_functionparams = true; internal_body << "\n" "{\n" ; if ( thirdpassinfo.extra.profiletype!="") { internal_body << " " << thirdpassinfo.extra.profiletype << " x( \"Virtual dispatch fn " << *virtfn->virtfn->items.back()->declarator->is_name() << "\");\n"; } /* The code we will generate typedefs two function pointer types. The first, 'cmm_FnPtr' is a pointer to the function-type that we are creating (dispatchfn), eg `int (*)( Base&, int, Base&)', while the second, `cmm_MatchFnPtr' is same type as 'matchfn', eg `bool (*)( Base&, Base&)'. */ parser::declarator_name_t* fnptrname = make_function_pointer( "cmm_FnPtr", bracketdecl->subtype->is_simple_function()); parser::declarator_name_t* matchfnptrname = make_function_pointer( "cmm_MatchFnPtr", matchfn->declarator->is_simple_function()); internal_body << " typedef "; fnptrname->output_complete( internal_body2); internal_body << ";\n typedef "; matchfnptrname->output_complete( internal_body2); internal_body << ";\n"; // Any type other than std::vector is required to take a second int template argument. if ( thirdpassinfo.extra.arraytype=="std::vector") internal_body << " typedef " << thirdpassinfo.extra.arraytype << "< const std::type_info*> cmm_arraytype;\n"; else internal_body << " typedef " << thirdpassinfo.extra.arraytype << "< const std::type_info*, " << virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->params.size() << "> cmm_arraytype;\n"; internal_body << " cmm_arraytype cmm_dynamictypes( " << virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->num_virtparams << ");\n" " cmm_FnPtr cmm_fn;\n" ; if ( thirdpassinfo.extra.profiletype!="") { internal_body << " {\n" << " " << thirdpassinfo.extra.profiletype << " x( \"Setting up array of typeids\");\n"; } int num_virtual_params = 0; { unsigned int vparam_i = 0; {for ( unsigned int i=0; ivirtfn->items.back()->declarator->is_simple_function()->parameters->params.size(); ++i) { parser::declarator_names_t* vparam_declnames = virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->params[i]; if ( vparam_declnames->prefix->ContainsType( typeid( parser::keyword_virtual))) { //debug << "fn->parameters->params.size() = " << fn->parameters->params.size() << "\n"; //debug << "i=" << i << "\n"; //debug << "vparam_i=" << vparam_i << "\n"; parser::name_t* name = fn->parameters->params[vparam_i]->items.back()->declarator->is_name()->name; internal_body << " assert( &" << (*name) << ");\n" << " cmm_dynamictypes[ " << vparam_i << "] = &typeid( " << (*name) << ");\n"; ++vparam_i; ++num_virtual_params; } }} } if ( thirdpassinfo.extra.profiletype!="") { internal_body << " }\n" << " {\n" << " " << thirdpassinfo.extra.profiletype << " x( \"Looking up in map\");\n"; } if ( thirdpassinfo.extra.profiletype!="") internal_body << " }\n"; if ( thirdpassinfo.extra.profiletype!="") { internal_body << " " << thirdpassinfo.extra.profiletype << " x( \"Resolving new overload\");\n"; } // Make 2D matrix of comparisons of implementations. internal_body << " int cmm_implcomparisons[" << virtfn->impls.size() << "][" << virtfn->impls.size() << "] =\n" " {" ; std::vector< std::vector< int> > implcomp( virtfn->impls.size()); {for ( unsigned int i=0; iimpls.size(); ++i) { implcomp[i].resize( virtfn->impls.size()); if ( i>0) internal_body << ","; internal_body << "\n { "; for ( unsigned int j=0; jimpls.size(); ++j) { if ( j>0) internal_body << ", "; internal_body << CompareImplPtrs0( virtfn->impls[i], virtfn->impls[j]); } internal_body << "}"; }} internal_body << "\n" " };\n"; internal_body << " struct cmm_ImplInfo\n" " {\n" " cmm_MatchFnPtr matchfn;\n" " cmm_FnPtr callfn;\n" " }\n" " cmm_impls[] =\n" " {" ; {for ( cmm::ThirdPassInfo::VirtFn::impls_t::const_iterator impl=virtfn->impls.begin(); impl!=virtfn->impls.end(); ++impl) { if ( impl!=virtfn->impls.begin()) internal_body << ","; internal_body << "\n" " {\n" " "; (*impl)->implmatch->items.back()->declarator->is_name()->name->output( internal_body2); internal_body << ",\n" " "; (*impl)->implcall->items.back()->declarator->is_name()->name->output( internal_body2); internal_body << "\n" " }"; }} internal_body << "\n" " };\n" " int cmm_bestimplnum = -1;\n" " for ( unsigned int cmm_impl=0; cmm_impl<" << virtfn->impls.size() << "; ++cmm_impl)\n" " {\n" " if ( cmm_impls[ cmm_impl].matchfn( "; { unsigned int vparam_i = 0; {for ( unsigned int i=0; ivirtfn->items.back()->declarator->is_simple_function()->parameters->params.size(); ++i) { parser::declarator_names_t* vparam_declnames2 = virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->params[i]; if ( vparam_declnames2->prefix->ContainsType( typeid( parser::keyword_virtual))) { parser::name_t* name = fn->parameters->params[vparam_i]->items.back()->declarator->is_name()->name; if ( vparam_i > 0) internal_body << ", "; internal_body << (*name); ++vparam_i; } }} } internal_body << "))\n" " {\n" " if ( cmm_bestimplnum == -1)\n" " { // This is the first matching implementation\n" " cmm_bestimplnum = cmm_impl;\n" " }\n" " else\n" " { // We already have a matching implementation number cmm_bestimplementation that is at least as derived as number cmm_impl\n" " if ( cmm_implcomparisons[ cmm_bestimplnum][ cmm_impl] == 0)\n" " { // Both impls cmm_bestimpl and cmm_impl are equally specialised, so the call is ambiguous\n" " //throw std::runtime_error( \"Ambiguous multiple dispatch for virtual function `" << *virtfn->virtfn->items.back()->declarator << "'\");\n" ; if ( thirdpassinfo.extra.no_exceptions_in_generated_code) { internal_body << " std::cerr << cmm_old_exception_ambiguous( \"" << virtfn->virtfn->items.back()->declarator->output_compact_tostring() << "\", " << num_virtual_params << ", &cmm_dynamictypes[ 0]).what() << \"\\n\";\n" " std::cerr << \"cmm dispatch code is calling exit(1);\\n\";\n" " exit(1);\n" " // We are assuming that the items in cmm_dynamictypes are contiguous in memory\n" ; } else { internal_body << " throw cmm_old_exception_ambiguous( \"" << virtfn->virtfn->items.back()->declarator->output_compact_tostring() << "\", " << num_virtual_params << ", &cmm_dynamictypes[ 0]);\n" " // We are assuming that the items in cmm_dynamictypes are contiguous in memory\n" ; } internal_body << " }\n" " else if ( cmm_implcomparisons[ cmm_bestimplnum][ cmm_impl] < 0)\n" " { // Impl cmm_bestimplnum is more specialised than Impl cmm_impl, so\n" " // do_t nothing.\n" " }\n" " }\n" " }\n" " }\n" " //if ( cmm_bestimplnum == -1) throw std::runtime_error( \"Unmatched multiple dispatch for virtual function `" << *virtfn->virtfn->items.back()->declarator << "'\");\n" ; if ( thirdpassinfo.extra.no_exceptions_in_generated_code) { internal_body << " if ( cmm_bestimplnum == -1)\n" " {\n" " std::cerr << cmm_old_exception_unmatched( \"" << virtfn->virtfn->items.back()->declarator->output_compact_tostring() << "\", " << num_virtual_params << ", &cmm_dynamictypes[ 0]).what() << \"\\n\";\n" " std::cerr << \"cmm dispatch code is calling exit(1);\\n\";\n" " exit(1);\n" " }\n" ; } else { internal_body << " if ( cmm_bestimplnum == -1) throw cmm_old_exception_unmatched( \"" << virtfn->virtfn->items.back()->declarator->output_compact_tostring() << "\", " << num_virtual_params << ", &cmm_dynamictypes[ 0]);\n" " // We are assuming that the items in cmm_dynamictypes are contiguous in memory\n" ; } internal_body << " cmm_fn = cmm_impls[ cmm_bestimplnum].callfn;\n" "return cmm_fn;\n" "}\n"; ; std::string* b = new std::string( internal_body.str()); // str().c_str() doesn't seem to work... parser::misc_t* newbody = new parser::misc_t; newbody->set_text( b->c_str()); declterm->terminator = newbody; debug0 << "Created lookup fn: " << (*declterm) << "\n"; return declnames; } parser::declarator_names_t* cmm::MakeDispatchFn( cmm::ThirdPassInfo::VirtFn* virtfn, const cmm::ThirdPassInfo& thirdpassinfo) { debug0 << "cmm::MakeDispatchFn called\n"; std::stringstream internal_body; if ( virtfn->impls.size()==0) throw exception_stream() << "Virtual function `" << *virtfn->virtfn << "' has no implementations"; std::sort( virtfn->impls.begin(), virtfn->impls.end(), CompareImplPtrs); /* The dispatch function that we create will be in the form of a declarator_names_t */ parser::declarator_names_t* declnames = new parser::declarator_names_t; parser::declarator_terminator_t* declterm = new parser::declarator_terminator_t; // declnames will contain one declterminator. declnames->items.push_back( declterm); declnames->declleft = virtfn->virtfn->declleft; // The left-most type is same as that of the virtual fun. parser::declarator_name_t* declname = new parser::declarator_name_t; declterm->declarator = declname; declname->name = virtfn->virtfn->items.front()->declarator->is_name()->name; declname->subtype = virtfn->virtfn->items.front()->declarator->is_name()->subtype; assert( declname->name); parser::function_t* fn = declname->is_simple_function(); // we need easy access to this later. assert( fn); parser::ensure_parameter_names( declname->subtype->is_simple_function()->parameters); parser::outstream_t internal_body2( internal_body); internal_body2.remove_virtual_from_functionparams = true; internal_body << "\n" "{\n" ; if ( thirdpassinfo.extra.profiletype!="") { internal_body << " " << thirdpassinfo.extra.profiletype << " x( \"Virtual dispatch fn " << *virtfn->virtfn->items.back()->declarator->is_name() << "\");\n"; } /* 'cmm_FnPtr' is a pointer to the function-type that we are creating (dispatchfn), eg `int (*)( Base&, int, Base&)'. */ parser::declarator_name_t* fnptrname = make_function_pointer( "cmm_FnPtr", fn); internal_body << " typedef "; fnptrname->output_complete( internal_body2); internal_body << ";\n"; // Any custom arraytype (from -array option) is required to take a second int template argument. if ( thirdpassinfo.extra.arraytype=="std::vector") internal_body << " typedef " << thirdpassinfo.extra.arraytype << "< const std::type_info*> cmm_arraytype;\n"; else internal_body << " typedef " << thirdpassinfo.extra.arraytype << "< const std::type_info*, " //<< virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->params.size() << fn->parameters->num_virtparams << "> cmm_arraytype;\n"; internal_body << " static " << thirdpassinfo.extra.maptype << "< cmm_arraytype, " << (*fnptrname->name) << "> cmm_dispatchcache;\n" " cmm_arraytype cmm_dynamictypes( " << virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->num_virtparams << ");\n" ; if ( thirdpassinfo.extra.profiletype!="") { internal_body << " {\n" << " " << thirdpassinfo.extra.profiletype << " x( \"Setting up array of typeids\");\n"; } { // Setup the array of typeids to contain the type of the virtual parameters. unsigned int vparam_i = 0; {for ( unsigned int i=0; ivirtfn->items.back()->declarator->is_simple_function()->parameters->params.size(); ++i) { parser::declarator_names_t* declnames = virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->params[i]; if ( declnames->prefix->ContainsType( typeid( parser::keyword_virtual))) { parser::name_t* name = fn->parameters->params[i]->items.back()->declarator->is_name()->name; internal_body << " cmm_dynamictypes[ " << vparam_i << "] = &typeid( " << (*name) << ");\n"; ++vparam_i; } }} assert( vparam_i == fn->parameters->num_virtparams); } if ( thirdpassinfo.extra.profiletype!="") { internal_body << " }\n" << " {\n" << " " << thirdpassinfo.extra.profiletype << " x( \"Looking up in map\");\n"; } internal_body << " cmm_FnPtr cmm_fn = cmm_dispatchcache[ cmm_dynamictypes];\n"; if ( thirdpassinfo.extra.profiletype!="") internal_body << " }\n"; internal_body << " if ( !cmm_fn)\n" " {\n" " cmm_fn = " << *declname->name << "_cmm_lookup( " ; { // output the parameters to be passed to the ..._cmm_loopup function unsigned int vparam_i = 0; {for ( unsigned int i=0; ivirtfn->items.back()->declarator->is_simple_function()->parameters->params.size(); ++i) { parser::declarator_names_t* declnames = virtfn->virtfn->items.back()->declarator->is_simple_function()->parameters->params[i]; if ( declnames->prefix->ContainsType( typeid( parser::keyword_virtual))) { parser::name_t* name = fn->parameters->params[i]->items.back()->declarator->is_name()->name; if ( vparam_i > 0) internal_body << ", "; internal_body << (*name); ++vparam_i; } }} } internal_body << ");\n" " cmm_dispatchcache[ cmm_dynamictypes] = cmm_fn;\n" " // cache the fnptr so we don't need to call ..._cmm_lookup function next time.\n" " }\n" " return cmm_fn( " ; // Output each of our parameters, in call to the implementation function we have found. {for ( unsigned int i=0; iparameters->params.size(); ++i) { //declarator_terminator_t* declterm = dispatchfn->declarator->is_simple_function()->parameters->params[i]->items.back(); parser::declarator_terminator_t* declterm = fn->parameters->params[i]->items.back(); parser::declarator_name_t* declname = dynamic_cast< parser::declarator_name_t*>( declterm->declarator->is_name()); if ( !declname->name) throw std::logic_error( "Param hasn't a name"); if ( i!=0) internal_body << ", "; internal_body << (*declname->name); }} internal_body << ");\n" "}\n" ; std::string* b = new std::string( internal_body.str()); // str().c_str() doesn't seem to work... parser::misc_t* newbody = new parser::misc_t; newbody->set_text( b->c_str()); declterm->terminator = newbody; //debug << "Created dispatch fn: " << (*declnames) << "\n"; return declnames; } void cmm::OutputPreDispatchCode( std::ostream& out, cmm::ThirdPassInfo::VirtFn& virtfn, const cmm::ThirdPassInfo& thirdpassinfo) { parser::outstream_t out2( out); out2.remove_virtual_from_functionparams = true; out << thirdpassinfo.extra.mapinclude << "\n" << thirdpassinfo.extra.profileinclude << "\n" << "#include \n" << "#include \n" << "#include \n" << "#include \n" // shouldn't be needed, but STLport's std::runtime_error c'tr doesn't take a char* otherwise... << "#include \n" << "\n" << "#ifndef cmm_OLD_EXCEPTIONCLASSES\n" " #define cmm_OLD_EXCEPTIONCLASSES\n" " struct cmm_old_exception : std::exception\n" " { // base class for exceptions thrown by cmm dispatch code.\n" " protected:\n" " cmm_old_exception( int numparams, const std::type_info** types0)\n" " : types( types0, types0 + numparams)\n" " {}\n" " void settext( const std::string& message0)\n" " { // We append type information to the given message.\n" " this->message = message0;\n" " this->message += \" Virtual params are: ( \";\n" " for ( types_t::const_iterator it=types.begin(); it!=types.end(); ++it)\n" " {\n" " if ( it!=types.begin()) this->message += \", \";\n" " this->message += (*it)->name();\n" " }\n" " this->message += \").\";\n" " }\n" " public:\n" " virtual const char* what() const throw()\n" " {\n" " return this->message.c_str();\n" " }\n" " virtual ~cmm_old_exception() throw()\n" " {\n" " }\n" " typedef std::vector< const std::type_info*> types_t;\n" " types_t types;\n" " std::string message;\n" " };\n" " struct cmm_old_exception_unmatched : cmm_old_exception\n" " {\n" " cmm_old_exception_unmatched( const char* fnname, int numparams, const std::type_info** types0)\n" " : cmm_old_exception( numparams, types0)\n" " {\n" " settext( std::string( \"Unmatched virtual dispatch for virtual function `\") + fnname + \"'.\");\n" " }\n" " };\n" " struct cmm_old_exception_ambiguous : cmm_old_exception\n" " {\n" " cmm_old_exception_ambiguous( const char* fnname, int numparams, const std::type_info** types0)\n" " : cmm_old_exception( numparams, types0)\n" " {\n" " settext( std::string( \"Ambiguous virtual dispatch for virtual function `\") + fnname + \"'.\");\n" " }\n" " };\n" "#endif\n" "\n" ; // Output prototypes of call and match functions for each implemnetation. for ( cmm::ThirdPassInfo::VirtFn::impls_t::const_iterator impl=virtfn.impls.begin(); impl!=virtfn.impls.end(); ++impl) { out << "extern "; (*impl)->implmatch->output( out2); out << "extern "; (*impl)->implcall->output( out2); } }