#ifdef WIN32 #pragma warning(disable: 4786) // Stop warnings about truncated identifiers in debug info #endif #include #include #include #include #include #include "cmm.h" #include "parser2.h" #include "exceptionstream.h" #include "tempfile.h" #include "debug.h" using namespace parser; using namespace cmm; void check( const cmm::multimethod_t& multimethod) { (void) multimethod; assert( multimethod.getimplfn->declleft); assert( multimethod.fn->declleft); assert( multimethod.getimplfn->items.size()==1); assert( multimethod.getimplfn->items.back()->declarator); assert( multimethod.getimplfn->items.back()->declarator->is_simple_function()); assert( multimethod.getimplfn->items.back()->declarator->is_simple_function()->get_declarator_left()); } std::ostream& operator << ( std::ostream& out, const cmm::multimethod_t& multimethod) { check( multimethod); out << "cmm::secondpass_info::multimethod at " << &multimethod << ": "; if ( multimethod.fn) out << "fn=" << multimethod.fn << "=" << multimethod.fn->output_compact_tostring(); else out << ""; out << "\nparamsinfo.size()=" << multimethod.parameters.size() << "\n"; assert( multimethod.getimplfn->items.front()->get_declarator_left()); return out; } namespace { bool NameIsImpl( declarator_t& virt, declarator_t& impl) /* Returns true iff impl's name makes it a possible implementation of virtual function 'virt'. This is defined as the same name with a trailing '_' Eg. if virtual function name is `foo::bar', then all implementations will have name `foo::bar_'. */ { //debug << "NameIsImpl, " << virt << ", " << impl << "\n"; debug_TRACE; name_t* virtname = dynamic_cast< const declarator_name_t*>( &virt)->name; name_t* implname = dynamic_cast< const declarator_name_t*>( &impl)->name; if ( !virtname || !implname) return false; // impl's leaf-name should be virt's name with a trailing '_' const name_element_normal_t* virtleaf = dynamic_cast< const name_element_normal_t*>( virtname->elements.back()); const name_element_normal_t* implleaf = dynamic_cast< const name_element_normal_t*>( implname->elements.back()); if ( !virtleaf || !implleaf) return false; const identifier_t& virtleafid = *virtleaf->identifier; const identifier_t& implleafid = *implleaf->identifier; int virtleaf_len = virtleafid.end-virtleafid.begin; int implleaf_len = implleafid.end-implleafid.begin; //debug << "virtleaf=" << *virtleaf << ", implleaf=" << *implleaf << "\n"; if ( virtleaf_len + 1 != implleaf_len) { debug0 << "wrong length\n"; return false; } if ( implleafid.end[-1]!='_') { debug0 << "impl leaf name doesn't end with `_'."; return false; } if ( 0 != strncmp( virtleafid.begin, implleafid.begin, virtleaf_len)) { debug0 << "impl leaf name isn't virt leaf name + `_'\n"; return false; } // if_t we get here, impl's leaf name is virt's leaf name plus trailing `_'. debug0 << "checking that both names are defined in the same namespace.\n"; bool ret = NamespacesEq( *virtname, *implname); debug0 << "returning " << ret << "\n"; return ret; } class_t* FindClass( const secondpass_info& info, name_t* name) /* Looks for class with the given name. Returns NULL if not present. Could use std::find, but this would involve a separate comparison function that compares the dereferenced pointers (or use of things in that probably don't work in VC6). */ { debug_TRACE; debug0 << "FindClass looking for " << *name << "\n"; assert( name); // first check whether the name is a typedef {for ( unsigned int i=0; i( typede->declnames); assert( declnames); for ( unsigned int j=0; jitems.size(); ++j) { declarator_terminator_t* declterm = declnames->items[j]; declarator_t* decl = declterm->declarator; declarator_name_t* declname = decl->is_name(); assert( declname); if ( *declname->name == *name) { //debug << "found matching typedef: " << *typede << "\n"; if ( declarator_left_t* declleft=dynamic_cast< declarator_left_t*>( declname->subtype)) { if ( class_t* clas=dynamic_cast< class_t*>( declleft->name)) { //debug << "returning matching class " << *clas << "\n"; return clas; } } //debug << "type " << *name << " is a typedef, but not for a simple class"; return NULL; } } }} {for ( unsigned int i=0; ioutput_complete( out); std::cerr << "'\n`"; clas.name->output_complete( out); std::cerr << "'\n";*/ if ( *clas.name == *name) return &clas; }} debug0 << "Couldn't find class " << *name << "\n"; return NULL; } bool GetDerivation( cmm::parameter_t& multimethod_parameter, cmm::parameter_t& implementation_parameter, const secondpass_info& info, name_t* multimethod_type, name_t* implementation_type) /* if_t impltype is derived from virttype, appends derivation details to paraminfo.derivation and paraminfo_virtfn, and returns true. else returns false, with possibly bogus items appended to paraminfo. */ { debug_TRACE; assert( multimethod_type); assert( implementation_type); debug0 << "GetDerivation called, virt=" << *multimethod_type << ", impl=" << *implementation_type << "\n"; class_t* virtclass = FindClass( info, multimethod_type); class_t* implclass = FindClass( info, implementation_type); if ( !virtclass) throw exception_stream() << "Virtual type `" << *multimethod_type << "' is not a class"; if ( !implclass) return false; { // check modifiers match assert( multimethod_parameter.declnames); assert( implementation_parameter.declnames); declarator_left_t* virtualparam_left = multimethod_parameter.declnames->declleft; declarator_left_t* implementation_left = implementation_parameter.declnames->declleft; assert( virtualparam_left); assert( implementation_left); if ( (!virtualparam_left->modifiers) != (!implementation_left->modifiers)) { return false; // one has modifiers, other doesn't. } if ( virtualparam_left->modifiers && implementation_left->modifiers) { if ( *virtualparam_left->modifiers != *implementation_left->modifiers) { debug0 << "different modifiers: `" << *virtualparam_left->modifiers << "' and `" << *implementation_left->modifiers << "'\n"; return false; } } } if ( *virtclass->name == *implclass->name) { implementation_parameter.derivation.push_back( implclass); debug0 << "GetDerivation Returning true\n"; return true; } else { debug0 << "Classes virt=" << *virtclass->name << " and impl=" << *implclass->name << " different\n"; debug0 << "implclass " << *implclass->name << " has " << implclass->baseclasses->items.size() << " bases\n"; for ( unsigned int i=0; ibaseclasses->items.size(); ++i) { name_t* implbase = implclass->baseclasses->items[ i]->name; if ( GetDerivation( multimethod_parameter, implementation_parameter, info, multimethod_type, implbase)) { implementation_parameter.derivation.push_back( implclass); /* Sould maybe carry on in loop and check there aren't other matching base classes - this would be an error in cmm source?*/ return true; } } return false; } return false; // to stop gcc getting confused when debug_TRACE is active } void OutputImplID( std::ostream& out, const cmm::parameters_t& types) /* Outputs the virtual parameters types in 'impl' in a form suitable for appending to a C++ identifier. For example: class Base {...}; class Derived : Base {...}; class Derived2 : Derived {...}; void foo( virtual Base& b); void foo_( Derived2& b); Here, the ImplId for implementation `foo' will be: _cmm_classtype3_4_Base7_Derived_8Derived2 This is used to generate names for the two support functions that are generated for each implementation, which in the above example would be: */ { debug_TRACE; //debug << "OutputImplID, size=" << types.size() << "\n"; out << types.size() << '_'; {for ( unsigned int j=0; jderivation.size() = " << parameter->derivation.size() << "\n"; debug0 << "parameter->declnames = " << *parameter->declnames << "\n"; out << parameter->derivation.size() << '_'; /* non virtual params have derivation.size()==0. */ for ( unsigned int k=0; kderivation.size(); ++k) { std::stringstream temp; outstream_t outstream( temp); assert( parameter->derivation[k]); assert( parameter->derivation[k]->name); parameter->derivation[k]->name->output_compact( outstream); int classname_len = temp.str().size(); out << classname_len; out << temp.str(); } }} } void AddVirtualMangling( name_t*& name, const cmm::parameters_t& parameters) /* Changes name to point to a new name that has implementation mangling information appended. Eg foo_ -> foo_cmm_params_cmm_class_Base_cmm_class_Derived */ { debug_TRACE; std::stringstream buffer; OutputImplID( buffer, parameters); add_suffix( name, buffer.str().c_str()); } declarator_name_t* EnsureName( declarator_t*& decl, int uid) { debug_TRACE; std::stringstream buffer; // gcc-2.95.3 fails with internal error if this is defined after the next return statement. declarator_name_t* declname = dynamic_cast< declarator_name_t*>( decl); if ( declname) return declname; buffer << "cmm_" << uid; std::string& s = *new std::string; s = buffer.str(); lexer_t lexer( "", s.c_str()); parser::context_t context; name_t* name = get_name( lexer, context); declname = new declarator_name_t; declname->name = name; declname->subtype = decl; decl = declname; //debug << "created declname: " << *declname << "\n"; return declname; } bool IsConst( const declarator_left_t& declleft) /* Returns true iff the specified declarator's modifiers includes `const'. */ { if ( !declleft.modifiers) return false; for ( unsigned int i=0; iitems.size(); ++i) { if ( typeid( *declleft.modifiers->items[i])==typeid( parser::keyword_const)) { return true; } } return false; } void AddModifiers( modifiers_t& modifiers, const modifiers_t& newmodifiers) /* Adds newmodifiers to modifiers, ommiting modifiers that are already in modifiers.*/ { debug0 << "AddModifiers, modifiers=" << modifiers << ", newmodifiers=" << newmodifiers << "\n"; for ( unsigned int i=0; ideclleft = new declarator_left_t; declnames->declleft->name = new keyword_bool( "bool "); declnames->declleft->modifiers = new modifiers_t; declnames->declleft->subtype = NULL; function_t* fn = new function_t; fn->subtype = declnames->declleft; fn->parameters = new function_parameters_t; fn->parameters->openround = new keyword_OPENROUND( "( "); fn->parameters->closeround = new keyword_CLOSEROUND( ")"); parser::context_t context; name_t* param_name = name_t::MakeName( "cmmtypes", context); keyword_void* param_lhs = new keyword_void( "void "); declarator_name_t* param_declname = new declarator_name_t; param_declname->name = param_name; declarator_left_t* param_declleft = new declarator_left_t; param_declleft->name = param_lhs; modifiers_t* param_modifiers = new modifiers_t; param_declleft->modifiers = param_modifiers; keyword_const* param_modifiers_const = new keyword_const( "const "); param_modifiers->items.push_back( param_modifiers_const); parser::keyword_STAR* star = new keyword_STAR( "*"); parser::pointer_t* param_ptr1 = new parser::pointer_t; param_ptr1->star = star; parser::pointer_t* param_ptr2 = new parser::pointer_t; param_ptr2->star = star; param_declname->subtype = param_ptr1; param_ptr1->subtype = param_ptr2; param_ptr2->subtype = param_declleft; declarator_terminator_t* param_declterm = new declarator_terminator_t; param_declterm->declarator = param_declname; declarator_names_t* param_declnames = new declarator_names_t; param_declnames->items.push_back( param_declterm); param_declnames->declleft = param_declleft; fn->parameters->params.push_back( param_declnames); // The parameters for the implmatch function are only the virtual parameters: #ifdef __GNUG__ std::stringstream* buffer0; buffer0 = MakeStringStream(); std::stringstream& buffer = *buffer0; //new std::stringstream; #else std::stringstream buffer; #endif outstream_t buffer2( buffer); buffer2.remove_static_virtual_prefixes = true; // not safe for top-level items, but we only use this buffer for nested itemd. buffer << "\n{\n"; unsigned int implmatch_param_number = 0; {for ( unsigned int i=0; imultimethod->parameters.size(); ++i) { //assert( implparam!=implfn->parameters->params.end()); //debug << "looking at param " << (**virtparam) << "\n"; //debug << "prefix=" << *(*virtparam)->prefix << "\n"; debug0 << "implmatch, looking at param " << *implinfo->multimethod->parameters[i]->declnames << "\n"; if ( implinfo->multimethod->parameters[i]->is_virtual) { if ( implinfo->multimethod->parameters[i]->is_templatespec_virtual) { buffer << " if ( !cmm_dynamic_test< "; (*implinfo->parameters)[i]->virtual_classname->output( buffer2); buffer << " >("; buffer << "*static_cast< const "; implinfo->multimethod->parameters[i]->declnames->items.back()->declarator->subtype->output_complete( buffer2); buffer << "*>(" << " cmmtypes[ " << implmatch_param_number << "]))) return false;\n" ; //debug << "just added param, fn is: " << *fn << "\n"; } else { bool is_already_const = IsConst( *implinfo->multimethod->parameters[i]->declnames->items.back()->declarator->is_simple_reference()) ? true : false; buffer << " if ( !dynamic_cast< "; if ( !is_already_const) buffer << "const "; /* we are outputing a cast to const . but may be const already, and so we only output 'const' if is not const already - gcc gives error if it sees `const const'. */ buffer << implinfo->implfn->items.back()->declarator->is_simple_function()->parameters ->params[i]->get_single_declterm()->declarator ->is_simple_reference()->output_complete_tostring() << "*>( static_cast< const "; implinfo->multimethod->parameters[i]->virtual_classname->output( buffer2); buffer << "*>(" << " cmmtypes[ " << implmatch_param_number << "]))) return false;\n" ; //debug << "just added param, fn is: " << *fn << "\n"; } ++implmatch_param_number; } //debug << "param is not virtual: " << **virtparam << "\n"; }} buffer << " return true;\n" "}\n"; misc_t* sn = new misc_t; std::string* text = new std::string( buffer.str()); sn->set_text( text->c_str()); // Remove any trailing comma from the last virtual parameter. assert( !fn->parameters->params.empty()); fn->parameters->params.back()->items.back()->terminator = NULL; declarator_name_t* declname = new declarator_name_t; declname->name = dynamic_cast< declarator_name_t*>( implinfo->implfn->items.back()->declarator)->name; assert( declname->name); add_suffix( declname->name, "cmm_impmatch"); AddVirtualMangling( declname->name, *implinfo->parameters); declname->subtype = fn; declarator_terminator_t* declterm = new declarator_terminator_t; declterm->declarator = declname; declterm->terminator = sn; declnames->items.push_back( declterm); //debug << "******** made matchfun -s: " << *declnames << "\n"; //debug << debug_PLACE << "virtfn is " << *virtfn << "\n"; return declnames; } declarator_names_t* MakeImplMatch( const cmm::implementation_t* implinfo) /* Makes the 'match' function for a particular implementation. The generated function takes just the virtual parameters, and returns true iff the dynamic types match the implementation. Eg. int foo( virtual Base& a, int b, virtual Base2& c); int foo_( Derived& b, int b, Derived2& c) {...} - results in: bool foo_cmm_match_cmm_param_cmm_class_Base_cmm_class_Derived_cmm_param_cmm_class_Base2_cmm_class_Derived2( Base& a, Base2& c) { if ( !dynamic_cast< Derived*>( &a)) return false; if ( !dynamic_cast< Derived2*>( &c)) return false; return true; } */ { //debug << "Making matchfn for virtual function " << *implinfo->virtfn << ", impl=" << *implinfo->implfn << "\n"; debug_TRACE; declarator_names_t* declnames = new declarator_names_t; declnames->declleft = new declarator_left_t; declnames->declleft->name = new keyword_bool( "bool "); declnames->declleft->modifiers = new modifiers_t; declnames->declleft->subtype = NULL; function_t* fn = new function_t; fn->subtype = declnames->declleft; fn->parameters = new function_parameters_t; fn->parameters->openround = new keyword_OPENROUND( "( "); fn->parameters->closeround = new keyword_CLOSEROUND( ")"); // The parameters for the implmatch function are only the virtual parameters: #ifdef __GNUG__ std::stringstream* buffer0; buffer0 = MakeStringStream(); std::stringstream& buffer = *buffer0; //new std::stringstream; #else std::stringstream buffer; #endif outstream_t buffer2( buffer); buffer2.remove_virtual_from_functionparams = true; buffer << "\n{\n"; //assert( implinfo->virtfninfo->paramsinfo.size()==implinfo->virtfninfo->virtfn->items.size()); {for ( unsigned int i=0; imultimethod->parameters.size(); ++i) { debug0 << "implmatch: param " << i << ": is_virtual=" << implinfo->multimethod->parameters[i]->is_virtual << "\n"; if ( implinfo->multimethod->parameters[i]->is_virtual) { /* put a copy of the param into the new fn's param list. this allows us to modify the terminator - have to remove a `,' from last virtual param if there are non-virtual params after it. */ declarator_names_t* param_declnames = new declarator_names_t( *implinfo->multimethod->parameters[i]->declnames); param_declnames->items.back() = new declarator_terminator_t( *param_declnames->items.back()); fn->parameters->params.push_back( param_declnames); declarator_name_t* paramname = EnsureName( fn->parameters->params.back()->items.back()->declarator, i); buffer << " if ( !dynamic_cast< "; implinfo->multimethod->parameters[i]->virtual_classname->output( buffer2); buffer << "*>( &"; paramname->name->output( buffer2); buffer << ")) return false;\n"; //debug << "just added param, fn is: " << *fn << "\n"; } //debug << "param is not virtual: " << **virtparam << "\n"; }} buffer << " return true;\n" "}\n"; misc_t* sn = new misc_t; std::string* text = new std::string( buffer.str()); sn->set_text( text->c_str()); /* Remove any trailing comma from the last virtual parameter. we/ve been careful to make the params copies of the original, so this won't change the original param (this is test83). */ assert( !fn->parameters->params.empty()); fn->parameters->params.back()->items.back()->terminator = NULL; declarator_name_t* declname = new declarator_name_t; declname->name = dynamic_cast< declarator_name_t*>( implinfo->implfn->items.back()->declarator)->name; assert( declname->name); add_suffix( declname->name, "cmm_impmatch"); AddVirtualMangling( declname->name, *implinfo->parameters); declname->subtype = fn; declarator_terminator_t* declterm = new declarator_terminator_t; declterm->declarator = declname; declterm->terminator = sn; declnames->items.push_back( declterm); //debug << debug_PLACE << "virtfn is " << *virtfn << "\n"; //debug << "made matchfun " << *declnames << "\n"; return declnames; } declarator_names_t* MakeImplCall( const cmm::implementation_t* implinfo) /* Makes the 'call' function for a particular implementation. The generated function takes the same parameter types as the virtual function prototype, and calls the implementation, making casts on the assumtion that the dynamic types are appropriate. Eg. int foo( virtual Base& a, int b, virtual Base2& c); int foo_( Derived& b, int b, Derived2& c) {...} - results in: bool foo_cmm_call_cmm_param_cmm_class_Base_cmm_class_Derived_cmm_param_cmm_class_Base2_cmm_class_Derived2( Base& a, int b, Base2& c) { return foo( static_cast< Derived&>( a), b, static_cast< Derived2&>( c)); } */ { debug_TRACE; assert( implinfo); assert( implinfo->multimethod->fn); assert( implinfo->multimethod->fn->items.size() > 0); assert( implinfo->multimethod->fn->items.back()); assert( implinfo->multimethod->fn->items.back()->declarator); debug0 << "Making implcall for virtual function " << *implinfo->multimethod->fn << ", impl=" << *implinfo->implfn << "\n"; function_t* virtfn = implinfo->multimethod->fn->items.back()->declarator->is_simple_function(); //debug << debug_PLACE << "virtfn is " << *virtfn << "\n"; assert( implinfo->implfn); assert( implinfo->implfn->items.size() > 0); assert( implinfo->implfn->items.back()); assert( implinfo->implfn->items.back()->declarator); assert( virtfn); declarator_names_t* declnames = new declarator_names_t; declnames->declleft = implinfo->multimethod->fn->declleft; function_t* fn = new function_t; fn->subtype = virtfn->subtype; fn->parameters = new function_parameters_t; fn->parameters->openround = new keyword_OPENROUND( "( "); fn->parameters->closeround = new keyword_CLOSEROUND( ")"); #ifdef __GNUG__ std::stringstream* buffer0; buffer0 = MakeStringStream(); std::stringstream& buffer = *buffer0; //new std::stringstream; #else std::stringstream buffer; #endif outstream_t buffer2( buffer); buffer << "\n{\n" " return "; assert( implinfo->implfn->items.back()->declarator->is_name()); assert( implinfo->multimethod); implinfo->implfn->items.back()->declarator->is_name()->name->output( buffer2); buffer << "( "; {for ( unsigned int i=0; imultimethod->parameters.size(); ++i) { //debug << "outputing param\n"; //assert( implparam!=implfn->parameters->params.end()); if ( i>0) buffer << ", "; fn->parameters->params.push_back( implinfo->multimethod->parameters[i]->declnames); declarator_name_t* paramname = EnsureName( fn->parameters->params.back()->items.back()->declarator, i); debug0 << "implcall: param " << i << ": is_virtual=" << implinfo->multimethod->parameters[i]->is_virtual << "\n"; if ( implinfo->multimethod->parameters[i]->is_virtual) { //debug << "virtual impl param is: " << (**implparam) << "\n"; if ( implinfo->multimethod->parameters[i]->is_templatespec_virtual) { buffer << "cmm_static_cast /*template virtual param*/< "; (*implinfo->parameters)[i]->virtual_classname->output( buffer2); buffer << " >( " << paramname->name->output_compact_tostring() << ")" ; } else { buffer << "*static_cast /*non-template virtual param*/< " << implinfo->implfn->items.back()->declarator->is_simple_function() ->parameters->params[i]->get_single_declterm()->declarator ->is_simple_reference()->output_complete_tostring() //->subtype->output_complete_tostring() << "*>( &" << paramname->name->output_compact_tostring() << ")" ; } } else { // not virtual parameter, so pass teh parameter directly. paramname->name->output( buffer2); } }} buffer << ");\n" "}\n"; misc_t* sn = new misc_t; std::string* text = new std::string( buffer.str()); sn->set_text( text->c_str()); declarator_name_t* declname = new declarator_name_t; declname->name = dynamic_cast< declarator_name_t*>( implinfo->implfn->items.back()->declarator)->name; assert( declname->name); add_suffix( declname->name, "cmm_implcall"); AddVirtualMangling( declname->name, *implinfo->parameters); declname->subtype = fn; declarator_terminator_t* declterm = new declarator_terminator_t; declterm->declarator = declname; declterm->terminator = sn; declnames->items.push_back( declterm); //debug << "Made implcall " << *declnames << "\n"; return declnames; } bool HasVtable( const secondpass_info& info, class_t* clas) { for ( multiple_nodes_t::items_t::iterator it=clas->block->items.items.begin(); it!=clas->block->items.items.end(); ++it) { if ( declarator_names_t* declnames=dynamic_cast< declarator_names_t*>( (*it))) { if ( declnames->items.size()==1 && declnames->items[0]->declarator->is_simple_function() && declnames->prefix->ContainsType( typeid( keyword_virtual))) { //debug << "class " << *clas << " has vtable\n"; return true; } } } // if_t we reach here, clas doesn't have virtual fns, so we check base classes. for ( parser::baseclasses_t::items_t::iterator b=clas->baseclasses->items.begin(); b!= clas->baseclasses->items.end(); ++b) { class_t* b2 = FindClass( info, (*b)->name); if ( !b2) { //std::cerr << "HasBaseClass can't find definition of class `" << *(*b)->name << "'\n"; } else { if ( HasVtable( info, b2)) return true; } } //debug << "class " << *clas << " has no vtable\n"; return false; } bool HasBaseClass( const secondpass_info& info, class_t* clas, const char* baseclass) { for ( parser::baseclasses_t::items_t::iterator b=clas->baseclasses->items.begin(); b!= clas->baseclasses->items.end(); ++b) { class_t* b2 = FindClass( info, (*b)->name); if ( !b2) { //std::cerr << "HasBaseClass can't find definition of class `" << *(*b)->name << "'\n"; } else { if ( b2->name->elements.size()==1 && *b2->name->elements[0] == baseclass) { return true; } if ( HasBaseClass( info, b2, baseclass)) return true; } } return false; } bool AllParamsHaveSmallInts( const secondpass_info secondpassinfo, const cmm::multimethod_t& multimethod) { check( multimethod); //debug << "AllParamsHaveSmallInts: virtfninfo.paramsinfo.size()=" << virtfninfo.paramsinfo.size() << "\n"; assert( multimethod.getimplfn->items.front()->get_declarator_left()); for ( unsigned int i=0; iis_virtual) if ( !parameter->is_virtual) { continue; // a non-virtual param } class_t* clas = FindClass( secondpassinfo, parameter->virtual_classname); if ( !clas || !HasBaseClass( secondpassinfo, clas, "cmm_small_integer_typeid")) { //debug << "~AllParamsHaveSmallInts: virtfninfo.paramsinfo.size()=" << virtfninfo.paramsinfo.size() << "\n"; return false; } } //debug << "AllParamsHaveSmallInts returning true for virtfn\n"; //debug << "~AllParamsHaveSmallInts: virtfninfo.paramsinfo.size()=" << virtfninfo.paramsinfo.size() << "\n"; return true; } void OutputCmmMinusSDispatch( const secondpass_info& secondpassinfo, std::ostream& out, const cmm::multimethod_t& multimethod) /* Outputs a complete dispatch fn, which uses fns in cmm's dispatch.cpp file. The generated function takes the same parameter types as the virtual function prototype, and calls the implementation, making casts on the assumtion that the dynamic types are appropriate. Eg. */ { check( multimethod); debug_TRACE; debug0 << "Making -s dispatch for virtual function " << *multimethod.fn << "\n"; assert( multimethod.getimplfn->items.front()->get_declarator_left()); function_t* virtfn = multimethod.fn->items.back()->declarator->is_simple_function(); assert( virtfn); declarator_names_t* declnames = new declarator_names_t; declarator_name_t* declname = new declarator_name_t; declarator_terminator_t* declterm = new declarator_terminator_t; function_t* fn = new function_t( *virtfn); declname->name = multimethod.fn->items.back()->declarator->is_name()->name; assert( declname->name); declname->subtype = fn; declnames->items.push_back( declterm); declterm->declarator = declname; declnames->declleft = declterm->get_declarator_left(); for ( unsigned int i=0; ideclnames->get_single_declterm(); EnsureName( declterm->declarator, i); } out << "inline "; outstream_t out2( out); out2.remove_virtual_from_functionparams = true; declnames->output( out2); name_t* mangled_virt = dynamic_cast< declarator_name_t*>( multimethod.fn->items.back()->declarator)->name; int virt_initial_namelen = mangled_virt->end-mangled_virt->begin; AddVirtualMangling( mangled_virt, multimethod.parameters); out << "\n{\n"; out << " static cmm_virtualfn& virtualfn = cmm_get_virtualfn( \""; out << virt_initial_namelen << *mangled_virt << "\");\n"; declarator_name_t* fnptrname = make_function_pointer( "cmm_fntype", virtfn); out << " typedef "; fnptrname->output_complete( out2); out << ";\n"; out << " const void* params[] = { "; bool have_output_first_virt_param = false; for ( unsigned int i=0; iis_virtual) { if ( have_output_first_virt_param) out << ", "; out << "&"; out << *multimethod.parameters[i]->declnames->get_single_declterm()->declarator->is_name()->name; have_output_first_virt_param = true; } } out << "};\n"; if ( secondpassinfo.generate_small_ints || AllParamsHaveSmallInts( secondpassinfo, multimethod)) { out << " const int types[] = { "; bool have_output_first_virt_param = false; for ( unsigned int i=0; iis_templatespec_virtual) { out << "cmm_get_small_integer( " << *multimethod.parameters[i]->declnames->get_single_declterm()->declarator->is_name()->name << ")"; } else { out << *multimethod.parameters[i]->declnames->get_single_declterm()->declarator->is_name()->name << ".cmm_get_small_integer()" ; } } out << "};\n"; } else { bool have_output_first_virt_param = false; out << " const std::type_info* types[] = { "; for ( unsigned int i=0; iis_virtual) { if ( have_output_first_virt_param) out << ", "; have_output_first_virt_param = true; if ( multimethod.parameters[i]->is_templatespec_virtual) out << "&cmm_typeid( "; else out << "&typeid( "; out << *multimethod.parameters[i]->declnames->get_single_declterm()->declarator->is_name()->name; out << ")"; } } out << "};\n"; } out << " cmm_fntype cmm_fn=reinterpret_cast< cmm_fntype>( cmm_lookup( virtualfn, params, types));\n" << " return cmm_fn( "; /* We need to output all the parameters in this fn call, including the non-virtual parameters. */ {for ( unsigned int i=0; i0) out << ", "; out << *multimethod.parameters[i]->declnames->get_single_declterm()->declarator->is_name()->name; }} out << ");\n"; out << "}\n"; assert( multimethod.getimplfn->items.front()->get_declarator_left()); } void OutputCmmMinusSDispatchGetFnPtr( const secondpass_info& secondpassinfo, std::ostream& out, const cmm::multimethod_t& multimethod) /* Outputs a function that returns pointer to correct implementation for a particular set of virtual parameters. */ { check( multimethod); debug_TRACE; //debug << "Making -s getfn for virtual function " << *implinfo->virtfn << ", impl=" << *implinfo->implfn << "\n"; assert( multimethod.getimplfn->items.front()->get_declarator_left()); assert( multimethod.fn->declleft); declarator_names_t* declnames = multimethod.getimplfn; assert( declnames->declleft); declnames->get_single_declterm()->terminator = NULL; // is fn body or `;'. function_t* fn = declnames->get_single_declterm()->declarator->is_simple_function(); debug0 << debug_PLACE << "fn="<<*fn<<"\n"; ensure_parameter_names( fn->parameters); assert( fn->parameters->params.size()>0); /*for ( unsigned int i=0; ideclnames->get_single_declterm()->declarator, i); }*/ out << "inline "; outstream_t out2( out); out2.remove_virtual_from_functionparams = true; declnames->output( out2); name_t* mangled_virt = dynamic_cast< declarator_name_t*>( multimethod.fn->items.back()->declarator)->name; function_t* virtfn = multimethod.fn->get_single_declterm()->declarator->is_simple_function(); int virt_initial_namelen = mangled_virt->end - mangled_virt->begin; AddVirtualMangling( mangled_virt, multimethod.parameters); out << "\n{\n"; out << " static cmm_virtualfn& virtualfn = cmm_get_virtualfn( \"" << virt_initial_namelen << *mangled_virt << "\");\n" ; declarator_name_t* fnptrname = make_function_pointer( "cmm_fntype", virtfn); out << " typedef "; fnptrname->output_complete( out2); out << ";\n"; out << " const void* params[] = { "; for ( unsigned int i=0; iparameters->params.size(); ++i) { EnsureName( fn->parameters->params[i]->get_single_declterm()->declarator, i); if ( i) out << ", "; out << "&"; out << *fn->parameters->params[i]->get_single_declterm()->declarator->is_name()->name; } out << "};\n"; if ( secondpassinfo.generate_small_ints || AllParamsHaveSmallInts( secondpassinfo, multimethod)) { out << " const int types[] = { "; for ( unsigned int i=0; iparameters->params.size(); ++i) { if ( i) out << ", "; if ( multimethod.parameters[i]->is_templatespec_virtual) { out << "cmm_get_small_integer( " << *fn->parameters->params[i]->get_single_declterm()->declarator->is_name()->name << ")"; } else { out << *fn->parameters->params[i]->get_single_declterm()->declarator->is_name()->name << ".cmm_get_small_integer()" ; } } out << "};\n"; } else { out << " const std::type_info* types[] = { "; unsigned int param_number_in_virt_fn = 0; for ( unsigned int i=0; iparameters->params.size(); ++i) { for(;;) { if ( multimethod.parameters[ param_number_in_virt_fn]->is_virtual) break; ++param_number_in_virt_fn; assert( param_number_in_virt_fn < multimethod.parameters.size()); } if ( i) out << ", "; if ( multimethod.parameters[ param_number_in_virt_fn]->is_templatespec_virtual) out << "&cmm_typeid( "; else out << "&typeid( "; out << *fn->parameters->params[i]->get_single_declterm()->declarator->is_name()->name << ")" ; } out << "};\n"; } out << " return (cmm_fntype) (void*) cmm_lookup( virtualfn, params, types);\n"; out << "}\n"; assert( multimethod.getimplfn->items.front()->get_declarator_left()); } enum cmm_virtual_or_static { cmm_VIRTUAL, cmm_STATIC }; const std::type_info& get_type( cmm_virtual_or_static vs) { if ( vs==cmm_VIRTUAL) return typeid( keyword_virtual); if ( vs==cmm_STATIC) return typeid( keyword_static); assert( 0); abort(); } name_t* find_virtual_name( declarator_names_t* declnames, cmm_virtual_or_static vs, bool* is_templatespec_virtual=NULL) { debug0 << "find_virtual_name: declnames=" << *declnames << "\n"; declarator_terminator_t* declterm = declnames->get_single_declterm(); declarator_left_t* declleft = declnames->declleft; assert( declleft); if ( declnames->prefix && declnames->prefix->ContainsType( get_type( vs))) { debug0 << "have found simple virtual/static\n"; declarator_left_t* virtparam_declleft = declterm->declarator->is_simple_reference(); if ( !virtparam_declleft) throw exception_stream() << "Expecting simple reference after `virtual/static'"; name_t* ret = dynamic_cast< name_t*>( virtparam_declleft->name); if ( !ret) throw exception_stream() << "Expecting simple reference to name after `virtual'"; if ( is_templatespec_virtual) *is_templatespec_virtual = false; return ret; } debug0 << "searching for virtual inside template specs, declleft is type " << typeid( *declleft).name() << " = " << declleft->output_complete_tostring() << "\n"; name_t* name = dynamic_cast< name_t*>( declleft->name); if ( !name || name->elements.empty()) return NULL; if ( template_specialisation_t* templatespec = name->elements.back()->templatespec) { debug0 << "name has trailing templatespec " << *templatespec << "\n"; for ( parser::template_specialisation_t::items_t::iterator it=templatespec->items.begin(); it != templatespec->items.end(); ++it) { debug0 << "tempaltespec item is: " << **it << ", type " << typeid( **it).name() << "\n"; if ( template_specialisation_item_type_t* classitem = dynamic_cast< template_specialisation_item_type_t*>( *it)) { debug0 << "item is a template_specialisation_item_type_t\n"; if ( classitem->declnames->prefix->ContainsType( get_type( vs))) { name_t* ret = dynamic_cast< name_t*>( classitem->declnames->get_single_declterm() ->get_declarator_left()->name); if ( !ret) throw exception_stream() << "Expecting name after `virtual' inside template spec"; debug0 << "have found virtual/static inside templatespec: " << *ret << ", is_templatespec_virtual=" << is_templatespec_virtual << "\n"; if ( is_templatespec_virtual) *is_templatespec_virtual = true; return ret; } else { debug0 << "item is not virtual/static\n"; } } } } return NULL; } bool fnparams_have_virtual( function_parameters_t* fnparams, cmm_virtual_or_static vs) { for ( unsigned int i=0; iparams.size(); ++i) { if ( find_virtual_name( fnparams->params[i], vs)) { debug0 << "found param with " << get_type( vs).name() << "\n"; return true; } } return false; } void find_virtual_name( cmm::parameter_t& virtparam, declarator_names_t* declnames) { virtparam.is_virtual = false; virtparam.is_templatespec_virtual = false; virtparam.virtual_classname = NULL; virtparam.declnames = declnames; if ( name_t* name = find_virtual_name( declnames, cmm_VIRTUAL, &virtparam.is_templatespec_virtual)) { virtparam.is_virtual = true; virtparam.virtual_classname = name; } else if ( name_t* name = find_virtual_name( declnames, cmm_STATIC, &virtparam.is_templatespec_virtual)) { virtparam.virtual_classname = name; } } function_t* MakeFnOnlyVirtualParams( const cmm::multimethod_t& multimethod) /* sets up parameters, leaving subtype as NULL.*/ { function_t* fn = new function_t; fn->parameters = new function_parameters_t; function_t* virtfn = multimethod.fn->items.back()->declarator->is_simple_function(); assert( virtfn); // might as well reuse the text for `(' and `)' in the virtual fn. fn->parameters->openround = virtfn->parameters->openround; fn->parameters->closeround = virtfn->parameters->closeround; unsigned int param_number = 0; {for ( function_parameters_t::params_t::const_iterator virtparam=virtfn->parameters->params.begin(); virtparam!=virtfn->parameters->params.end(); ++virtparam) { //if ( (*virtparam)->prefix && (*virtparam)->prefix->ContainsType( typeid( keyword_virtual))) if ( find_virtual_name( *virtparam, cmm_VIRTUAL)) { /* put a copy of the param into the new fn's param list. this allows us to modify the terminator - have to remove a `,' from last virtual param if there are non-virtual params after it. */ declarator_names_t* param_declnames = new declarator_names_t( **virtparam); param_declnames->items.back() = new declarator_terminator_t( *param_declnames->items.back()); fn->parameters->params.push_back( param_declnames); EnsureName( fn->parameters->params.back()->items.back()->declarator, param_number); ++param_number; } //debug << "param is not virtual: " << **virtparam << "\n"; }} /* Remove any trailing comma from the last virtual parameter. we/ve been careful to make the params copies of the original, so this won't change the original param (this is test83). */ assert( !fn->parameters->params.empty()); fn->parameters->params.back()->items.back()->terminator = NULL; return fn; } } cmm::parameters_t::parameters_t( declarator_names_t* declnames, const secondpass_info& secondpassinfo) : std::vector< parameter_t*>() { debug_TRACE; //debug << debug_PLACE << " parameters::parameters(), declnames=" << *declnames << "\n"; function_t* fn = declnames->items.back()->declarator->is_simple_function(); assert( fn); //debug << "num params=" << fn->parameters->params.size() << "\n"; for ( unsigned int param=0; paramparameters->params.size(); ++param) { this->push_back( new cmm::parameter_t); find_virtual_name( *this->back(), fn->parameters->params[ param]); if ( this->back()->is_virtual) { debug0 << "found virt param " << *fn->parameters->params[ param] << ", is_templatespec_virtual=" << this->back()->is_templatespec_virtual << "\n"; if ( !this->back()->virtual_classname) { debug0 << "expecting virtual_classname for " << *declnames << "\n"; } assert( this->back()->virtual_classname); class_t* c = FindClass( secondpassinfo, this->back()->virtual_classname); if ( !c) { std::cerr << "virtual param type `" << *this->back()->virtual_classname << "' is not a known class\n"; throw exception_stream() << "virtual param type `" << *this->back()->virtual_classname << "' is not a known class"; } this->back()->derivation.push_front( c); } } } namespace { enum cmm_comparison { cmm_comparison_LESSTHAN, cmm_comparison_GREATERTHAN, cmm_comparison_EQUAL, cmm_comparison_UNRELATED }; bool GetDerivation( const cmm::parameters_t& virt, cmm::parameters_t& impl, const cmm::secondpass_info& secondpassinfo) /* if impl's params are all derived from virt params, sets impl[].derivation to the intermediate class names, and returns true. else returns false. */ { debug_TRACE; if ( virt.size() != impl.size()) { debug << "virt.size() != impl.size()\n"; return false; // different num of params. } for ( unsigned int i=0; ideclnames << "'\n"; debug0 << "GetDerivation: looking at impl param `" << *impl[i]->declnames << "'\n"; if ( !virt[i]->is_virtual) { debug0 << "GetDerivation: skipping non-virtual param `" << *virt[i]->declnames << "\n"; continue; } if ( !impl[i]->virtual_classname) { debug0 << "GetDerivation: impl param doesn't have known type name\n"; return false; } impl[i]->derivation.clear(); debug0 << "GetDerivation, i=" << i << ", virt=" << *virt[i]->virtual_classname << "\n"; assert( virt[i]); assert( virt[i]->virtual_classname); if ( !GetDerivation( *virt[i], *impl[i], secondpassinfo, virt[i]->virtual_classname, impl[i]->virtual_classname)) { for ( unsigned int j=0; jderivation.clear(); } return false; } else { } } return true; } void AddImplToMatchingVirtFn( secondpass_info& secondpassinfo, declarator_names_t* implfn) /* if_t implfn is an implementation, adds it to secondpassinfo. */ { debug_TRACE; std::vector< int> near_matches; /* indexes into secondpassinfo.multimethods. these are virtual fns for which implfn has the right name to be an implementation, but unmatching parameters. */ function_t* fn = implfn->get_single_declterm()->declarator->is_simple_function(); assert( fn); for ( unsigned int virtfn_i=0; virtfn_iget_single_declterm()->get_declarator_left()); assert( multimethod.fn->items.size()==1); assert( multimethod.getimplfn->declleft); //debug << "TryGetImplInfo: virtfn is " << *multimethod.fn->items.back()->declarator << ", impl is " << *implfn << "\n"; //debug << "TryGetImplInfo: multimethod=" << multimethod << "\n"; if ( NameIsImpl( *multimethod.fn->get_single_declterm()->declarator, *implfn->get_single_declterm()->declarator)) { debug0 << "Found possible impl: " << *implfn << "\n"; if ( !fnparams_have_virtual( fn->parameters, cmm_STATIC)) { std::cerr << "cmm: Warning, ignoring possible multimethod implementation:\n" << "cmm: " << implfn->get_single_declterm()->declarator->output_compact_tostring() << "\n" << "cmm: - of multimethod:\n" << "cmm: " << multimethod.fn->items.back()->declarator->output_compact_tostring() << "\n" << "cmm: - because possible implementation doesn't have and any `static' parameters.\n" ; return; } cmm::parameters_t* parameters = new cmm::parameters_t( implfn, secondpassinfo); if ( GetDerivation( multimethod.parameters, *parameters, secondpassinfo)) { cmm::implementation_t* impl = new cmm::implementation_t; impl->parameters = parameters; //impl->virtfn = multimethod.fn; impl->implfn = implfn; impl->multimethod = &multimethod; debug0 << "handling implementation. impl->virtfn=" << *impl->multimethod->fn << "\n"; debug0 << "handling implementation. impl->implfn=" << *impl->implfn << "\n"; impl->implcall = MakeImplCall( impl); impl->implmatch = MakeImplMatch( impl); impl->implmatch_minuss = MakeImplMatch_CmmMinusS( impl); impl->multimethod = &multimethod; debug0 << "handling implementation2. impl->virtfn=" << *impl->multimethod->fn << "\n"; debug0 << "handling implementation2. impl->implfn=" << *impl->implfn << "\n"; debug0 << "TryGetImplInfo: created ipl, multimethod=" << *impl->multimethod << "\n"; multimethod.implementations.push_back( impl); secondpassinfo.implementations.push_back( impl); return; } else { debug0 << "GetDerivation failed\n"; near_matches.push_back( virtfn_i); delete parameters; } assert( multimethod.getimplfn->items.front()->get_declarator_left()); } } if ( near_matches.empty()) { if ( fnparams_have_virtual( fn->parameters, cmm_STATIC)) { std::cerr << "cmm: Warning, function:\n" << "cmm: " << implfn->get_single_declterm()->declarator->output_compact_tostring() << "\n" << "cmm: - looks like a multimethod implementation, but there is no prior matching\n" << "cmm: multimethod declaration.\n" ; } } else { std::cerr << "cmm: Warning, function:\n" << "cmm: " << implfn->get_single_declterm()->declarator->output_compact_tostring() << "\n" << "cmm: - looks like a multimethod implementation, but the parameters do not exactly match\n" << "cmm: any multimethods. Near-matching multimethod(s):\n" ; for ( int i=0; i<(int) near_matches.size(); ++i) { std::cerr << "cmm: " << secondpassinfo.multimethods[ near_matches[i]]->fn ->items.back()->declarator->output_compact_tostring() << "\n"; } } } struct Error2 : std::exception { Error2( node_t* node0, const char* text0) : node( node0), text() { debug_TRACE; text = text0; text += ": "; text += node0->output_tostring(); } virtual ~Error2() throw() {} virtual const char* what() const throw() { return this->text.c_str(); } node_t* node; std::string text; }; declarator_names_t* MakeMethodReflectFn( cmm::secondpass_info& secondpassinfo, node_t* ampersand, declarator_names_t* declnames) { debug_TRACE; if ( declnames->items.size() != 1) throw Error2( ampersand, "declnames->items.size() != 1. Expecting function declaration"); declarator_terminator_t* declterm = declnames->items[0]; if ( typeid( *declterm->terminator) != typeid( keyword_SEMICOLON)) throw Error2( ampersand, "typeid( *declterm->terminator) != typeid( keyword_SEMICOLON). Expecting function declaration"); declarator_name_t* declname = dynamic_cast< declarator_name_t*>( declterm->declarator); if ( !declname) throw Error2( ampersand, "!declname. Expecting function declaration"); if ( !declname->name) throw Error2( ampersand, "!declname->name. Expecting function declaration"); function_t* fn = declterm->declarator->is_simple_function(); if ( !fn) throw Error2( ampersand, "!fn. Expecting function declaration"); if ( fn->parameters->params.size() < 1) throw Error2( ampersand, "Function needs at least one parameter"); ensure_parameter_names( fn->parameters); declarator_names_t* param1_declnames = fn->parameters->params[0]; assert( param1_declnames->items.size() == 1); declarator_terminator_t* param1_declterm = param1_declnames->items[0]; declarator_t* param1_decl = param1_declterm->declarator; declarator_left_t* param1_type = param1_decl->is_simple_reference(); if ( param1_type) { debug0 << "param1_type=" << param1_type << "\n"; debug0 << "param1_type->name=" << param1_type->name << "\n"; } if ( !param1_type || !param1_type->name) { throw Error2( ampersand, "First param should be simple reference"); } /* we can handle either a `' or `struct ': */ name_t* param1_classname = dynamic_cast< name_t*>( param1_type->name); if ( !param1_classname) { debug0 << typeid( *param1_type->name).name() << "\n"; if ( class_fwd_t* classfwd = dynamic_cast< class_fwd_t*>( param1_type->name)) { param1_classname = classfwd->name; } } if ( !param1_classname) throw Error2( ampersand, "Need class or struct"); if ( fn->parameters->num_virtparams > 0) { // fixme: should output virtual fn. should also set a flag that forces // generation of serialisation fn for all derived classes. return declnames; } else { class_t* clas = FindClass( secondpassinfo, param1_classname); if ( !clas) throw Error2( ampersand, "Can't find class name"); debug0 << "have found class\n"; std::stringstream buffer; outstream_t buffer_outstream( buffer); buffer << declterm->Output2StringCompleteDeclOnly() << "\n"; buffer << "{\n"; //debug << "outputing recursive calls for class " << *clas << "\n"; for ( baseclasses_t::items_t::const_iterator base=clas->baseclasses->items.begin(); base!=clas->baseclasses->items.end(); ++base) { buffer << *declname->name << "cmm_reflect( "; buffer << "static_cast< "; if ( param1_type->modifiers) buffer << *param1_type->modifiers << " "; buffer << *(*base)->name << "&>( "; buffer << *dynamic_cast< declarator_name_t*>( fn->parameters->params[0]->items.front()->declarator)->name; buffer << ")"; buffer << ", typeid( " << (*base)->name->output_compact_tostring() << "), \"::"; buffer << (*base)->name->output_compact_tostring() << "\""; function_parameters_t::params_t::const_iterator param=fn->parameters->params.begin(); ++param; // skip first param. for ( ; param!=fn->parameters->params.end(); ++param) { buffer << ", " << *dynamic_cast< declarator_name_t*>( (*param)->items.front()->declarator)->name; } buffer << ");\n"; } for ( multiple_nodes_t::items_t::const_iterator classnode=clas->block->items.items.begin(); classnode!=clas->block->items.items.end(); ++classnode) { node_t* n = *classnode; debug0 << "looking at class's member " << *n << "\n"; debug0 << "declnames=" << dynamic_cast< declarator_names_t*>( n) << "\n"; if ( declarator_names_t* class_declnames = dynamic_cast< declarator_names_t*>( n)) { for ( declarator_names_t::items_t::const_iterator class_declterm=class_declnames->items.begin(); class_declterm!=class_declnames->items.end(); ++class_declterm) { //debug << "declnames item=" << typeid( **class_declterm).name() << "=" << **class_declterm << "\n"; if ( declarator_name_t* class_declname = dynamic_cast< declarator_name_t*>( (*class_declterm)->declarator)) { if ( !class_declname->is_simple_function()) { buffer << "\t" << *declname->name << "cmm_reflect( "; buffer << *dynamic_cast< declarator_name_t*>( fn->parameters->params[0]->items.front()->declarator)->name; buffer << "." << *class_declname->name; buffer << ", typeid( "; class_declnames->declleft->OutputLeft2( buffer_outstream); buffer << *class_declname->subtype << "), \""; class_declname->name->output_compact( buffer_outstream); buffer << "\""; function_parameters_t::params_t::const_iterator param=fn->parameters->params.begin(); ++param; // skip first param. for ( ; param!=fn->parameters->params.end(); ++param) { buffer << ", " << *dynamic_cast< declarator_name_t*>( (*param)->items.front()->declarator)->name; } buffer << ");\n"; } } } } } buffer << "}\n"; std::string* buffer2 = new std::string( buffer.str()); lexer_t lexer( "cmm-internal", buffer2->c_str()); context_t context; node_t* n = get_top_level_node( lexer, context); //debug << "generated reflect fn is " << *n << ", " << typeid( *n).name() << "\n"; //debug << *n; declarator_names_t* generatedfn = dynamic_cast< declarator_names_t*>( n); assert( generatedfn); return generatedfn; } } declarator_names_t* MakeMethodRecursiveFn( cmm::secondpass_info& secondpassinfo, node_t* ampersand, declarator_names_t* declnames) { debug_TRACE; if ( declnames->items.size() != 1) throw Error2( ampersand, "declnames->items.size() != 1. Expecting function declaration"); declarator_terminator_t* declterm = declnames->items[0]; if ( typeid( *declterm->terminator) != typeid( keyword_SEMICOLON)) throw Error2( ampersand, "typeid( *declterm->terminator) != typeid( keyword_SEMICOLON). Expecting function declaration"); declarator_name_t* declname = dynamic_cast< declarator_name_t*>( declterm->declarator); if ( !declname) throw Error2( ampersand, "!declname. Expecting function declaration"); if ( !declname->name) throw Error2( ampersand, "!declname->name. Expecting function declaration"); function_t* fn = declterm->declarator->is_simple_function(); if ( !fn) throw Error2( ampersand, "!fn. Expecting function declaration"); if ( fn->parameters->params.size() < 1) throw Error2( ampersand, "Function needs at least one parameter"); ensure_parameter_names( fn->parameters); declarator_names_t* param1_declnames = fn->parameters->params[0]; assert( param1_declnames->items.size() == 1); declarator_terminator_t* param1_declterm = param1_declnames->items[0]; declarator_t* param1_decl = param1_declterm->declarator; declarator_left_t* param1_type = param1_decl->is_simple_reference(); if ( !param1_type || !param1_type->name) throw Error2( ampersand, "First param should be simple reference"); name_t* param1_classname = dynamic_cast< name_t*>( param1_type->name); if ( !param1_classname) throw Error2( ampersand, "First param should be simple reference to class name"); if ( fn->parameters->num_virtparams > 0) { // fixme: should output virtual fn. should also set a flag that forces // generation of serialisation fn for all derived classes. return declnames; } else { class_t* clas = FindClass( secondpassinfo, param1_classname); if ( !clas) throw Error2( ampersand, "Can't find class name"); std::stringstream buffer; buffer << declterm->Output2StringCompleteDeclOnly() << "\n"; buffer << "{\n"; //debug << "outputing recursive calls for class " << *clas << "\n"; for ( baseclasses_t::items_t::const_iterator base=clas->baseclasses->items.begin(); base!=clas->baseclasses->items.end(); ++base) { /* output prototype of the function we are about to call. allows things to compile correctly, but gives link error if the required fn is not defined somewhere. */ if ( 0) { node_t* param1_type_name_original = param1_type->name; param1_type->name = (*base)->name; buffer << " extern " << *declnames; param1_type->name = param1_type_name_original; } // fixme - don't specify const in static_cast. buffer << " (void) " << *declname->name << "( "; buffer << "static_cast< "; if ( param1_type->modifiers) { //std::cerr << "param1_type->modifiers=" << *param1_type->modifiers << "\n"; buffer << *param1_type->modifiers << " "; } buffer << *(*base)->name << "&>( "; buffer << *dynamic_cast< declarator_name_t*>( fn->parameters->params[0]->items.front()->declarator)->name; buffer << ")"; function_parameters_t::params_t::const_iterator param=fn->parameters->params.begin(); ++param; // skip first param. for ( ; param!=fn->parameters->params.end(); ++param) { buffer << ", " << *dynamic_cast< declarator_name_t*>( (*param)->items.front()->declarator)->name; } buffer << ");\n"; } for ( multiple_nodes_t::items_t::const_iterator classnode=clas->block->items.items.begin(); classnode!=clas->block->items.items.end(); ++classnode) { node_t* n = *classnode; //debug << "looking at class's member " << *n << "\n"; //debug << "declnames=" << dynamic_cast< declarator_names_t*>( n) << "\n"; if ( declarator_names_t* class_declnames = dynamic_cast< declarator_names_t*>( n)) { for ( declarator_names_t::items_t::const_iterator class_declterm=class_declnames->items.begin(); class_declterm!=class_declnames->items.end(); ++class_declterm) { //debug << "declnames item=" << typeid( **class_declterm).name() << "=" << **class_declterm << "\n"; if ( declarator_name_t* class_declname = dynamic_cast< declarator_name_t*>( (*class_declterm)->declarator)) { if ( !class_declname->is_simple_function()) { // output prototype of fn we are about to call. if ( 0) { declarator_names_t* param0_declnames = fn->parameters->params[0]; declarator_left_t* param0_old_declleft2 = fn->parameters->params[0]->declleft; declarator_t* param0_old_declleft = param0_declnames->items[0]->declarator->subtype->subtype; param0_declnames->items[0]->declarator->subtype->subtype = class_declname->subtype; fn->parameters->params[0]->declleft = class_declnames->declleft; reference_t* param0_reference = dynamic_cast< reference_t*>( param0_declnames->items[0]->declarator->subtype); assert( param0_reference); modifiers_t* param0_old_modifiers = param0_reference->modifiers; param0_reference->modifiers = param0_old_declleft2->modifiers; buffer << " extern " << *declnames; // restore the function details: param0_declnames->items[0]->declarator->subtype->subtype = param0_old_declleft; fn->parameters->params[0]->declleft = param0_old_declleft2; param0_reference->modifiers = param0_old_modifiers; } // output the function call. buffer << " (void) " << *declname->name << "( "; buffer << *dynamic_cast< declarator_name_t*>( fn->parameters->params[0]->items.front()->declarator)->name; buffer << "." << *class_declname->name; function_parameters_t::params_t::const_iterator param=fn->parameters->params.begin(); ++param; // skip first param. for ( ; param!=fn->parameters->params.end(); ++param) { buffer << ", " << *dynamic_cast< declarator_name_t*>( (*param)->items.front()->declarator)->name; } buffer << ");\n"; } } } } } buffer << "}\n"; std::string* buffer2 = new std::string( buffer.str()); lexer_t lexer( "cmm-internal", buffer2->c_str()); context_t context; node_t* n = get_top_level_node( lexer, context); //debug << "generated rec fn is " << n << ", " << typeid( *n).name() << "\n"; //debug << *n; declarator_names_t* generatedfn = dynamic_cast< declarator_names_t*>( n); assert( generatedfn); return generatedfn; } assert( 0); return NULL; // keep gcc quiet when debug_TRACE is active. } bool InStd( const secondpass_info& /*info*/, class_t* clas) { /*if ( clas->name->namespac && clas->name->namespac->leafname) { debug << "class `" << *clas->name << "' is in namespace `" << *clas->name->namespac->leafname << "', parent=" << clas->name->namespac->parent << "\n"; }*/ if ( clas->name->namespac && clas->name->namespac->leafname && *clas->name->namespac->leafname=="std" //&& !clas->name->namespac->parent ) { //debug << "class `" << *clas->name << "' is in std\n"; return true; } else { //debug << "class `" << *clas->name << "' is not in std\n"; return false; } } void AddImplementationOf_cmm_get_small_integer( const secondpass_info& info, class_t* clas) /* if class has cmm_small_integer_typeid as a base class, add implementation of virtual method cmm_get_small_integer(). */ { //debug << "AddImplementationOf_cmm_get_small_integer: clas=`" << clas->name << "'\n"; if ( ( info.generate_small_ints && HasVtable( info, clas) && !InStd( info, clas)) || ( HasBaseClass( info, clas, "cmm_small_integer_typeid")) ) { debug << "Adding impl of cmm_get_small_integer() to class `" << *clas->name << "'\n"; assert( clas->block); misc_t* fn = new misc_t(); fn->set_text( " virtual int cmm_get_small_integer() const " "{ static int id=0; " "if ( !id) id = cmm_create_small_integer( typeid( *this)); " "return id; }" ); clas->block->items.items.push_back( fn); } } } void cmm::secondpass_info::AddItems( const std::vector< node_t*>& items) { debug_TRACE; //debug << "cmm::secondpass_info::AddItems\n"; for ( unsigned int i=0; i( items[i])) { //debug << "secondpass_info::secondpass_info() found namespace\n"; AddItems( namespac->items); } else if ( linkage_t* linkage=dynamic_cast< linkage_t*>( items[i])) { //debug << "secondpass_info::secondpass_info() found linkage block\n"; AddItems( linkage->items); } else { node_t* node = items[i]; if ( ampersand_node_t* ampersand = dynamic_cast< ampersand_node_t*>( node)) { if ( *ampersand->name == "cmm_memberrecursivefn") { debug << "Handling @cmm_memberrecursivefn\n"; node_t* n = ampersand->node; declarator_names_t* declnames = dynamic_cast< declarator_names_t*>( n); if ( !declnames) throw Error2( ampersand, "@cmm_memberrecursivefn. Expecting function declaration"); debug << "fn is: " << *declnames; declarator_names_t* newfn = MakeMethodRecursiveFn( *this, ampersand, declnames); this->memberrecursives.push_back( newfn); node = newfn; } else if ( *ampersand->name == "cmm_memberreflectfn") { debug0 << "Handling @cmm_memberreflectfn\n"; node_t* n = ampersand->node; declarator_names_t* declnames = dynamic_cast< declarator_names_t*>( n); if ( !declnames) throw Error2( ampersand, "@cmm_memberreflectfn. Expecting function declaration"); debug0 << "fn is: " << *declnames; declarator_names_t* newfn = MakeMethodReflectFn( *this, ampersand, declnames); this->memberrecursives.push_back( newfn); node = newfn; } else { throw Error2( ampersand, ( std::string( "unrecognised @ identifier ") + ampersand->name->output_compact_tostring()).c_str()); } } else { } /* note that we don't use `else if' next. this allows the previous code to replace items[i] with a declarator_names_t. */ if ( typedef_t* typede = dynamic_cast< typedef_t*>( node)) { this->typedefs.push_back( typede); } else if ( declarator_names_t* declnames=dynamic_cast< declarator_names_t*>( node)) { if ( declnames->declleft) { if ( class_t* clas=dynamic_cast< class_t*>( declnames->declleft->name)) { //debug << "found class ";// << (clas->name->output_complete( std::cerr),"") << "\n"; //debug << *clas << "\n"; AddImplementationOf_cmm_get_small_integer( *this, clas); this->classes.push_back( clas); } for ( declarator_names_t::items_t::const_iterator it=declnames->items.begin(); it!=declnames->items.end(); ++it) { declarator_terminator_t* declterm = *it; if ( function_t* fn=declterm->declarator->is_simple_function()) { declarator_names_t* thisfn = new declarator_names_t( *declnames); thisfn->items.clear(); thisfn->items.push_back( declterm); debug0 << "found function " << *thisfn << "\n"; //if ( fn->parameters->num_virtparams > 0) if ( fnparams_have_virtual( fn->parameters, cmm_VIRTUAL)) { // check we haven't already seen this virtual function debug0 << "fn " << *declnames << " has virtual params\n"; /*we have to compare name spearately - our operator== ignores names, in order to only take into account the types involved. should probably not use operator== for this...*/ declarator_name_t* fnname = declterm->declarator->is_name(); if ( !fnname) { std::cerr << "cmm: Expecting declname,...\n"; continue; } if ( !declterm->terminator || typeid( *declterm->terminator)!=typeid( keyword_SEMICOLON)) { std::cerr << "cmm: warning: ignoring possible multimethod:\n" << "cmm: " << declterm->declarator->output_compact_tostring() << "\n" << "cmm: - because it has a function body.\n" ; } else { bool is_duplicate = false; for ( multimethods_t::const_iterator it_virtfns=this->multimethods.begin(); it_virtfns!=this->multimethods.end(); ++it_virtfns) { declarator_name_t* existing_fnname = (*it_virtfns)->fn->items.front()->declarator->is_name(); assert( existing_fnname); if ( *fnname->name != *existing_fnname->name) continue; if ( *(*it_virtfns)->fn == *thisfn) { is_duplicate = true; std::cerr << "Found duplicate virtual function declaration `"; outstream_t outstream( std::cerr); thisfn->output_compact( outstream); std::cerr << "\n"; (*it_virtfns)->fn->output_compact( outstream); std::cerr << "\n"; break; } } if ( !is_duplicate) { //debug << "adding virtual fn\n"; this->multimethods.push_back( new multimethod_t( *this, thisfn, &compunit.filename, node)); } } } else //if ( fnparams_have_virtual( fn->parameters, cmm_STATIC)) { // check whether this is an implementation of a virtual fn /* we could only do this if fnparams_have_virtual( fn->parameters, cmm_STATIC), but for now we check all functions - gives useful diagnostic if the user forgets to put `static' in front of implementation's virtual parareters.*/ if ( declnames->semicolon) { debug0 << "ignoring possible implementation - item is fn declaration\n"; // function declaration, not definition. } else { AddImplToMatchingVirtFn( *this, thisfn); } } } } } } } } } cmm::secondpass_info::secondpass_info( const compilation_unit_t& compunit0, const char* outputfilename, bool generate_small_ints0) : compunit( compunit0), outfilename( outputfilename), classes(), typedefs(), multimethods(), implementations(), memberrecursives(), generate_small_ints( generate_small_ints0) { debug_TRACE; AddItems( compunit.items); } cmm::implementation_t::implementation_t() : filename(), //virtfn(), implfn(), implcall(), implmatch(), implmatch_minuss(), parameters(), multimethod() { } namespace { function_t* MakeDummyFn() { function_t* fn = new function_t; declarator_left_t* declleft = new declarator_left_t; declleft->name = new keyword_void( "void"); fn->subtype = declleft; fn->parameters = new function_parameters_t; fn->parameters->openround = new keyword_OPENROUND( "("); fn->parameters->closeround = new keyword_CLOSEROUND( ")"); return fn; } } #ifndef NDEBUG namespace { std::set< void*> global_multimethods; } #endif cmm::multimethod_t::~multimethod_t() { debug0 << "cmm::multimethod_t::~multimethod_t(): this=" << ((void*) this) << "\n"; assert( 1==global_multimethods.count( ((void*) this))); #ifndef NDEBUG global_multimethods.erase( ((void*) this)); #endif } cmm::multimethod_t::multimethod_t( const secondpass_info& secondpassinfo, parser::declarator_names_t* fn0, const std::string* filename0, parser::node_t* original_node0) : fn( fn0), getimplfn( NULL), parameters( fn, secondpassinfo), implementations(), filename( filename0), original_node( original_node0) { assert( fn0); assert( 0==global_multimethods.count( this)); debug0 << debug_PLACE << " multimethod::multimethod, fn=" << *fn << "\n"; //debug << "cmm::secondpass_info::multimethod::multimethod: paramsinfo.size()=" << this->paramsinfo.size() << "\n"; //debug << "cmm::secondpass_info::multimethod::multimethod: *this=" << *this << "\n"; function_t* fn = MakeFnOnlyVirtualParams( *this); this->getimplfn = new parser::declarator_names_t; declarator_terminator_t* declterm = new declarator_terminator_t; declarator_name_t* declname = new declarator_name_t; this->getimplfn->items.push_back( declterm); declterm->declarator = declname; declterm->terminator = new keyword_SEMICOLON( ";"); declname->name = this->fn->items.back()->declarator->is_name()->name; assert( declname->name); declname->subtype = fn; add_suffix( declname->name, "_cmm_getimpl"); pointer_t* ptr = new pointer_t; ptr->star = new keyword_STAR( "*"); bracket_declarator_t* bracketdecl = new bracket_declarator_t; ptr->subtype = bracketdecl; bracketdecl->open = new keyword_OPENROUND( "("); bracketdecl->close = new keyword_CLOSEROUND( ")"); bracketdecl->subtype = this->fn->items.front()->declarator->subtype; fn->subtype = ptr; this->getimplfn->declleft = this->getimplfn->items.front()->get_declarator_left(); assert( this->getimplfn->declleft); assert( this->getimplfn->items.front()->get_declarator_left()); assert( this->getimplfn->items.front()->declarator->is_simple_function()); /*debug << "this->getimplfn->items.front()->declarator->is_simple_function() is:\n"; for ( declarator_t* d=this->getimplfn->items.front()->declarator->is_simple_function(); d; d=d->subtype) { debug << "{ " << typeid( *d).name() << "}\n"; } debug << "--end--\n";*/ assert( this->getimplfn->items.front()->declarator->is_simple_function()->get_declarator_left()); debug0 << "multimethod::multimethod: this->getimplfn->declleft=" << *this->getimplfn->declleft << "\n"; debug0 << "multimethod::multimethod: bracketdecl->subtype->subtype=" << *bracketdecl->subtype->subtype << "\n"; debug0 << "multimethod::multimethod: getimplfn is: " << *this->getimplfn << "\n"; check( *this); debug0 << "cmm::multimethod_t::multimethod_t(): this=" << ((void*) this) << "\n"; #ifndef NDEBUG assert( global_multimethods.count( ((void*) this))==0); global_multimethods.insert( ((void*) this)); #endif } namespace { void OutputImplementationRegistration( std::ostream& out, const cmm::implementation_t& implementation) { debug_TRACE; //debug << "OutputImplementationRegistration, *implementation.virtfninfo=" << *implementation.virtfninfo << "\n"; out << "static cmm_implementation_holder "; outstream_t out2( out); name_t* impl_name0 = dynamic_cast< declarator_name_t*>( implementation.implfn->items.back()->declarator)->name; name_t* impl_name1 = impl_name0; int impl_basenamelen = impl_name1->end-impl_name1->begin; AddVirtualMangling( impl_name1, *implementation.parameters); assert( &implementation); assert( implementation.multimethod); assert( implementation.multimethod->fn); assert( implementation.multimethod->fn->get_single_declterm()->declarator); name_t* virt_name0 = dynamic_cast< declarator_name_t*>( implementation.multimethod->fn->get_single_declterm()->declarator) ->name; name_t* virt_name1 = virt_name0; int virt_basenamelen = virt_name1->end-virt_name1->begin; //debug << "just about to call AddVirtualMangling. implementation.virtfninfo->paramsinfo.size()=" << implementation.virtfninfo->paramsinfo.size() << "\n"; AddVirtualMangling( virt_name1, implementation.multimethod->parameters); assert( implementation.multimethod->getimplfn->items.front()->get_declarator_left()); out << *impl_name1; out << "_placeholder(\n"; out << " \""; out << virt_basenamelen << *virt_name1; out << "\",\n"; out << " \""; out << impl_basenamelen << *impl_name1; out << "\",\n"; out << " " << *dynamic_cast< declarator_name_t*>( implementation.implmatch->items.back()->declarator)->name << ",\n"; out << " reinterpret_cast< cmm_fnptr>( "; out << *dynamic_cast< declarator_name_t*>( implementation.implcall->items.back()->declarator)->name; out << "));\n"; } } struct linenumbered_streambuf : std::streambuf /* crude wrapping streambuf that keeps track of linenumbers.*/ { explicit linenumbered_streambuf( std::ostream& base0) : std::streambuf(), base( &base0), line_number( 1) {} virtual int overflow( int c) { if ( c=='\n') { ++this->line_number; //std::cerr << "line_number=" << this->line_number << "\n"; } this->base->put( c); return 0; } int get_line_number() { return this->line_number; } private: std::ostream* base; int line_number; }; void cmm::secondpass_info::OutputTranslatedSource( bool no_hash_lines, parser::exceptions_translation exceptiontranslation, bool cmm_minus_s) const { debug_TRACE; //std::ofstream out0( outfilename.c_str()); temp_file_t out0; linenumbered_streambuf buf( out0.stream); std::ostream out2( &buf); //if ( !out0) throw exception_stream() << "Can't open file `" << outfilename.c_str() << "' for writing"; //outstream_t out( out0.stream); outstream_t out( out2); out.remove_virtual_from_functionparams = true; out.exceptiontranslation = exceptiontranslation; if ( out.exceptiontranslation==exceptionstranslation_FUDGE) { out.out << "namespace std { class exception; }\n" "extern std::exception* Cmm_ExceptionFudge_Get();\n" "extern void Cmm_ExceptionFudge_Throw( const std::exception& e);\n" "extern void Cmm_ExceptionFudge_Throw();\n"; debug << "Afer 4 lines, buf.line_number=" << buf.get_line_number() << "\n"; } if ( this->generate_small_ints) { out.out << //"namespace std { struct type_info; }\n" "extern int\n" " cmm_create_small_integer(\n" " const std::type_info& type);\n" ; } if ( !no_hash_lines) out.out << "#line 1 \"" << compunit.filename << "\"\n"; for ( unsigned int i=0; ioutput( out); for ( secondpass_info::multimethods_t::const_iterator multimethod = this->multimethods.begin(); multimethod != this->multimethods.end(); ++multimethod) { if ( (*multimethod)->original_node == item) { debug0 << "have just output node for a virtual fn. getimplfn is: " << *(*multimethod)->getimplfn << "\n"; // output prototype of getimplfn just after the virtual fn prototype. (*multimethod)->getimplfn->output( out); break; } } } if ( cmm_minus_s && this->multimethods.size()>0) { out.out << "\n"; out.out << "#line " << buf.get_line_number() << " \"" << outfilename << "\"\n"; out.out << "// These are also in cmm's dispatch.h header.\n" "#ifndef CMM_DISPATCH_H\n" "#include \n" "struct cmm_virtualfn;\n" "struct cmm_implementation;\n" "typedef bool (*cmm_matchfn)( const void** params);\n" "typedef void (*cmm_fnptr)( void);\n" "\n" "extern cmm_virtualfn&\n" " cmm_get_virtualfn(\n" " const char* virt_spec);\n" "extern cmm_implementation&\n" " cmm_register_implementation(\n" " const char* virt_spec,\n" " const char* impl_spec,\n" " cmm_matchfn fn_match,\n" " cmm_fnptr fn_call);\n" "extern cmm_fnptr\n" " cmm_lookup(\n" " cmm_virtualfn& virtfn,\n" " const void** params,\n" " const std::type_info** types);\n" "extern cmm_fnptr\n" " cmm_lookup(\n" " cmm_virtualfn& virtfn,\n" " const void** params,\n" " const int* types);\n" "struct cmm_implementation_holder\n" "{\n" " cmm_implementation_holder(\n" " const char* virt_spec, \n" " const char* impl_spec, \n" " cmm_matchfn fn_match, \n" " cmm_fnptr fn_call);\n" " \n" " ~cmm_implementation_holder();\n" " \n" " cmm_implementation& handle;\n" "};\n" "#endif\n" "\n" ; } for ( unsigned int i=0; iimplementations.size(); ++i) { // output match and call fns. /*debug << "cmm::secondpass_info::OutputTranslatedSource: *virtfnimpls[impl]->virtfninfo=" << *virtfnimpls[impl]->virtfninfo << "\n";*/ this->implementations[i]->implcall->output( out); if ( !cmm_minus_s) { this->implementations[i]->implmatch->output( out); } else { assert( this->implementations[i]->implmatch_minuss); this->implementations[i]->implmatch_minuss->output( out); OutputImplementationRegistration( out.out, *this->implementations[i]); } } if ( cmm_minus_s) { for ( unsigned int i=0; imultimethods.size(); ++i) { //debug << "calling OutputCmmMinusSDispatch\n"; assert( this->multimethods[ i]->getimplfn->declleft); assert( this->multimethods[ i]->fn->declleft); assert( this->multimethods[ i]->fn->items.back()->declarator->is_simple_function()->get_declarator_left()); OutputCmmMinusSDispatchGetFnPtr( *this, out.out, *this->multimethods[ i]); assert( this->multimethods[ i]->getimplfn->declleft); OutputCmmMinusSDispatch( *this, out.out, *this->multimethods[ i]); assert( this->multimethods[ i]->getimplfn->declleft); } } for ( unsigned int memberrecursive=0; memberrecursive < this->memberrecursives.size(); ++memberrecursive) { this->memberrecursives[ memberrecursive]->output( out); } out0.close_and_move( outfilename.c_str()); } void cmm::secondpass_info::OutputImplDetails( std::ostream& out0) const { debug_TRACE; outstream_t out( out0); out.remove_virtual_from_functionparams = true; for ( unsigned int multimethods_i=0; multimethods_imultimethods.size(); ++multimethods_i) { // output text of the virtual function. const multimethod_t& multimethod = *this->multimethods[multimethods_i]; out0 << "virtualfunction " << '"' << outfilename << "\" " << *multimethod.fn; //<< "\n"; //debug << "virtual function is: " << (*virtfn->fn) << "\n"; //debug << "Generating .cmmi file, virt fn is " << *virtfn->fn << "\n"; // now outputinfo on each implimentation of this virtual function. for ( unsigned int impl_i=0; impl_imultimethod == &multimethod); { out0 << "implementation \"" << this->outfilename << "\" "; out0 << implementation->parameters->size() << ' '; // should be same as num virt params. for ( unsigned int i=0; iparameters->size(); ++i) { out0 << (*implementation->parameters)[i]->derivation.size() << ' '; for ( unsigned int j=0; j<(*implementation->parameters)[i]->derivation.size(); ++j) { (*implementation->parameters)[i]->derivation[j]->name->output_compact( out); out0 << ' '; } } out0 << "\n"; // Now output prototypes of the match and dispatch functions. declarator_names_t* declnames = implementation->implmatch; declnames->declleft->OutputLeft2( out); declnames->items.back()->declarator->output( out); out0 << ";\n"; declnames = implementation->implcall; declnames->declleft->OutputLeft2( out); declnames->items.back()->declarator->output( out); out0 << ";\n"; } } out0 << "\n"; } }