#ifdef WIN32 #pragma warning(disable: 4786) // Stop warnings about truncated identifiers in debug info #endif #include "parser2.h" #include "../utils/debug.h" #include #include #include #include #include #include std::ostream& operator<<( std::ostream& out, const parser::context_t::location_t l) { if (0) ; else if (l==parser::context_t::NORMAL) out << "context_t::NORMAL"; else if (l==parser::context_t::FNPARAMS) out << "context_t::FNPARAMS"; else if (l==parser::context_t::EXPRESSION) out << "context_t::EXPRESSION"; else if (l==parser::context_t::TEMPLATESPEC) out << "context_t::TEMPLATESPEC"; else assert( 0); return out; } std::ostream& operator<<( std::ostream& out, const parser::context_t& context) { out << "detailed parse=" << context.detailedparse << ", location=" << context.location ; return out; } using namespace parser; namespace parser { node_t::node_t() : begin( NULL), end( NULL) { /* Could keep a register of all nodes allocated in some static member, so that things can be cleaned up */ //std::cerr << "node_t::node_t: type=" << typeid( *this).name() << "\n"; ++node_t::number_of_nodes; } void node_t::set_text( const char* text) { this->begin = text; for ( this->end=begin; *end; ++end) {} } void node_t::set_text( const char* begin0, const char* end0) { this->begin = begin0; this->end = end0; } std::string node_t::output_tech_tostring() const { std::stringstream buffer; outstream_t out( buffer); this->output_tech( out); return buffer.str(); } std::string node_t::output_tostring() const { std::stringstream buffer; outstream_t out( buffer); this->output( out); return buffer.str(); } std::string node_t::output_compact_tostring( const outstream_t& flags) const { std::stringstream buffer; outstream_t out( buffer, flags); out.output_extra = false; this->output( out); std::string s = buffer.str(); // in `s', replace all sequences of white space by single space. bool last_was_space = false; std::string::size_type to=0; std::string::size_type from=0; for ( ; fromoutput( out); out.out << "]"; } bool operator == ( const node_t& a, const char* s) { /*debug0 << "comparing node type " << typeid( a).name() << " len " << a.end-a.begin << " `" << a << "' with char* len " << strlen( s) << " `" << s << "'\n";*/ if ( a.end-a.begin != (int) strlen( s)) { debug0 << "different lens: " << a.end-a.begin << ", " << strlen( s) << "\n"; return false; } if ( 0==strncmp( a.begin, s, a.end-a.begin)) { debug0 << "node is equal\n"; return true; } else { debug0 << "node is not equal\n"; return false; } } int node_t::number_of_nodes = 0; node_t::~node_t() { --node_t::number_of_nodes; } outstream_t::outstream_t( std::ostream& out0) : out( out0), remove_virtual_from_functionparams( false), remove_static_virtual_prefixes( false), include_declleft( false), caller_dispatch( false), exceptiontranslation( exceptionstranslation_PRESERVE), output_main( true), output_space( true), output_extra( true) { } outstream_t::outstream_t( std::ostream& out0, const outstream_t& outstream) : out( out0), remove_virtual_from_functionparams( outstream.remove_virtual_from_functionparams), include_declleft( outstream.include_declleft), caller_dispatch( false), exceptiontranslation( outstream.exceptiontranslation), output_main( outstream.output_main), output_space( outstream.output_space), output_extra( outstream.output_extra) { } } /* TryGet--typename--( lexer_t&) - tries to read given type from lexer. Returns NULL if no match, else pointer to new instance of type on heap. Get--typename--( lexer_t&) - As TryGet, except throws if no match. */ /* Next anonymous namespace contains all the internal parsing code */ namespace { template< class A, class B> bool TryGetMulti( lexer_t& lexer, A*& a, B*& b) // does two-item lookahead. { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); if ( ( a=TryGet< A>( lexer)) && ( b=TryGet< B>( lexer))) return true; lexmark.Backtrack(); return false; } keyword_t* IsClassOrStruct( node_t* node) { debug_TRACE_PRETTY; keyword_t* k = dynamic_cast< keyword_class*>( node); if ( !k) k = dynamic_cast< keyword_struct*>( node); return k; } square_brackets_t* TryGetSquareBrackets( lexer_t& lexer, const context_t& /*context*/) { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); if ( keyword_OPENSQUARE* open = TryGet< keyword_OPENSQUARE>( lexer)) { if ( keyword_CLOSESQUARE* close = TryGet< keyword_CLOSESQUARE>( lexer)) { square_brackets_t* sb = new square_brackets_t; sb->begin = open->begin; sb->open = open; sb->close = close; sb->end = close->end; return sb; } } lexmark.Backtrack(); return NULL; } /* Making this a template fn that takes he type of the opening bracket is much neater, but VC6 screws up badly on the template parameter - something to do with a template fn GetBlock calling another template function TryGetBlock? */ block_t* TryGetBlock( lexer_t& lexer, const context_t& context0, const std::type_info& type=typeid( keyword_OPENCURLY), bool expect_bad_nestings=false) { debug_TRACE_PRETTY; context_t context( context0); context.location = context_t::NORMAL; debug0 << "TryGetBlock called for type " << type.name() << ", detaileparse=" << context.detailedparse << "'\n"; lexer_mark_t lexmark( lexer); if ( context.detailedparse) { keyword_t* open = NULL; if ( 0) ; else if ( type==typeid( keyword_OPENCURLY)) open = TryGet< keyword_OPENCURLY>( lexer); else if ( type==typeid( keyword_OPENROUND)) open = TryGet< keyword_OPENROUND>( lexer); else if ( type==typeid( keyword_OPENSQUARE)) open = TryGet< keyword_OPENSQUARE>( lexer); else throw parser::error_t( lexer, "internal_t error - only able to look " "for (...), {...} or [...]"); if ( !open) return NULL; block_t* block = new block_t; block->begin = open->begin; block->open = open; for(;;) { // look for closing bracket if ( false || ( type==typeid( keyword_OPENCURLY) && TryPeek< keyword_CLOSECURLY>( lexer)) || ( type==typeid( keyword_OPENROUND) && TryPeek< keyword_CLOSEROUND>( lexer)) || ( type==typeid( keyword_OPENSQUARE) && TryPeek< keyword_CLOSESQUARE>( lexer)) ) { block->close = Get< keyword_t>( lexer); block->end = block->close->end; break; } if ( TryGet< endoffile_t>( lexer)) { lexmark.Backtrack(); throw parser::error_t( lexer, "End of file reached inside block"); } node_t* n = NULL; if ( type != typeid( keyword_OPENCURLY)) n = tryget_expression( lexer, context); if ( !n) n = tryget_top_level_node( lexer, context); if ( !n) { lexmark.Backtrack(); return NULL; } block->items.items.push_back( n); } return block; } else { //HierProf_SCOPEDBLOCK( "non-detailed parse"); debug0 << "in non-detailed-parse block reader\n"; block_t* block = NULL; std::vector< const std::type_info*> nesting; for(;;) { //HierProf_SCOPEDBLOCK( "non-detailed parse loop"); //static int ref1 = HierProf_InitBlock( "ref1"); //HierProf_StartClock1( ref1); if ( TryGet< endoffile_t>( lexer)) { lexmark.Backtrack(); throw parser::error_t( lexer, "End of file reached inside block"); } const std::type_info* closetype=NULL; { //HierProf_SCOPEDBLOCK( "keyword_OPENCURLY"); { //HierProf_SCOPEDBLOCK( "keyword_OPENCURLY"); if ( TryPeek< keyword_OPENCURLY>( lexer)) { closetype = &typeid( keyword_CLOSECURLY); } } { //HierProf_SCOPEDBLOCK( "keyword_OPENROUND"); if ( TryPeek< keyword_OPENROUND>( lexer)) { closetype = &typeid( keyword_CLOSEROUND); } } { //HierProf_SCOPEDBLOCK( "keyword_OPENSQUARE"); if ( TryPeek< keyword_OPENSQUARE>( lexer)) { closetype = &typeid( keyword_CLOSESQUARE); } } } //HierProf_StopClock1( ref1); //static int ref2 = HierProf_InitBlock( "ref2"); //HierProf_StartClock1( ref2); if ( closetype) { //HierProf_SCOPEDBLOCK( "non-detailed parse-loop-closetype"); keyword_t* open = Get< keyword_t>( lexer); if ( nesting.size()==0) { if ( typeid( *open) != type) return NULL; block = new block_t; block->open = open; block->begin = open->begin; } else block->items.items.push_back( open); nesting.push_back( closetype); continue; } if ( !block) return NULL; // must have found open before anything else. //HierProf_StopClock1( ref2); //static int ref3 = HierProf_InitBlock( "ref3"); //HierProf_StartClock1( ref3); keyword_t* close = NULL; if ( !close) close=TryGet< keyword_CLOSECURLY>( lexer); if ( !close) close=TryGet< keyword_CLOSEROUND>( lexer); if ( !close) close=TryGet< keyword_CLOSESQUARE>( lexer); if ( close) { //HierProf_SCOPEDBLOCK( "non-detailed parse-loop-close"); if ( typeid( *close) != *nesting.back()) { std::cerr << "Found close type " << typeid(*close).name() << ", expecting " << nesting.back()->name() << "\n"; if ( expect_bad_nestings) { lexmark.Backtrack(); return NULL; } throw parser::error_t( lexer, "Bad bracket-nesting"); } nesting.pop_back(); if ( nesting.size()==0) { block->end = close->end; block->close = close; break; } else { block->items.items.push_back( close); } continue; } //HierProf_StopClock1( ref3); //HierProf_SCOPEDBLOCK( "non-detailed parse-loop-push_back"); block->items.items.push_back( lexer.GetNext()); } debug0 << "non-detailed parse block ending\n"; return block; } } block_t* GetBlock( lexer_t& lexer, const context_t& context, const std::type_info& type=typeid( keyword_OPENCURLY)) { debug_TRACE_PRETTY; block_t* ret = TryGetBlock( lexer, context, type); if ( !ret) { throw parser::error_t( lexer, std::string( "Expecting block with bracket type `") + type.name() + "'"); } return ret; } template_specialisation_t* TryGetTemplateSpec( lexer_t& lexer, context_t& context) /* Looks for `<...>', e.g. in template specialisation. Not used after seeing top-level `template' keyword.*/ { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); keyword_LT* lt = TryGet< keyword_LT >( lexer); if ( !lt) return NULL; template_specialisation_t* templatespec = new template_specialisation_t; templatespec->lt = lt; templatespec->begin = lt->begin; debug0 << "TryGetTemplateSpec():\n"; // use context where `,' terminates expressions, rather than being an operator. context_t context2( context); context2.location = context_t::TEMPLATESPEC; for(;;) { if ( ( templatespec->gt = TryGet< keyword_GT>( lexer))) break; template_specialisation_itembase_t* item = NULL; if ( declarator_names_t* declnames = tryget_declarator_names_internal( lexer, context2, true)) { template_specialisation_item_type_t* typeitem = new template_specialisation_item_type_t; typeitem->declnames = declnames; item = typeitem; } else { if ( expression_t* expr = tryget_expression( lexer, context2)) { debug0 << "read expression `" << *expr << "'\n"; template_specialisation_item_expression_t* otheritem = new template_specialisation_item_expression_t; otheritem->expression = expr; otheritem->terminating_comma = TryGet< keyword_COMMA>( lexer); item = otheritem; } } if ( !item) { // clean up. we don't bother to clean up completely at the moment. for ( int i=0; i<(int)templatespec->items.size(); ++i) { delete( templatespec->items[i]); } delete templatespec; templatespec = NULL; lexmark.Backtrack(); break; } templatespec->items.push_back( item); debug0 << "found templatebrackets item: `" << item->output_compact_tostring() << "'\n"; } if ( templatespec) debug0 << "context is " << context << ", returning template brackets: " << templatespec->output_compact_tostring() << "\n"; return templatespec; } parser::template_single_t* TryGetTemplateSingle( parser::lexer_t& lexer, parser::context_t& context) /* Looks for `<...>' following `template. */ { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); keyword_template* template_keyword = TryGet< keyword_template>( lexer); if ( !template_keyword) return NULL; keyword_LT* lt = TryGet< keyword_LT >( lexer); if ( !lt) return NULL; debug0 << "TryGetTemplateSingleBrackets() - have found `<'\n"; template_single_t* templatesingle = new template_single_t; templatesingle->templat = template_keyword; templatesingle->lt = lt; templatesingle->begin = lt->begin; debug0 << "looking inside <...>\n"; // use context where `,' terminates expressions, rather than being an operator. context_t context2( context); context2.location = context_t::TEMPLATESPEC; for(;;) { if ( ( templatesingle->gt = TryGet< keyword_GT>( lexer))) break; templatesingle_item_t* item = new templatesingle_item_t; item->class_or_typename = TryGet< keyword_class>( lexer); if ( !item->class_or_typename) item->class_or_typename = TryGet< keyword_typename>( lexer); context_t context2( context); context2.location = context_t::TEMPLATESPEC; if ( item->class_or_typename) { item->declnames = get_declarator_names_internal( lexer, context2, false); } else { item->declnames = get_declarator_names_internal( lexer, context2, true); } templatesingle->items.push_back( item); debug0 << "have found templatesingle_item_t: " << *item << "\n"; } templatesingle->end = templatesingle->gt->end; debug0 << "TryGetTemplateSingle returning: " << *templatesingle << "\n"; return templatesingle; } template_t* TryGetTemplate( lexer_t& lexer, context_t& context) // looks for `template <...>'. { debug_TRACE_PRETTY; template_t* templat = NULL; while ( template_single_t* ts = TryGetTemplateSingle( lexer, context)) { if ( !templat) { templat = new template_t; templat->begin = ts->begin; } templat->singles.push_back( ts); } if ( templat) templat->end = lexer.GetPos(); return templat; } bool NextIdentifierIs( lexer_t& lexer, const char* name) { debug_TRACE_PRETTY; if ( identifier_t* id=TryPeek< identifier_t>( lexer)) { return *id == name; } return false; } internal_t* TryGetInternal( lexer_t& lexer, context_t& context); void SetModifiers( lexer_t& lexer, context_t& context, modifiers_t& modifiers) { debug_TRACE_PRETTY; modifiers.begin = lexer.GetPos(); for(;;) { if ( NextIdentifierIs( lexer, "__const") || NextIdentifierIs( lexer, "__inline") || TryPeek< keyword_const>( lexer) || TryPeek< keyword_volatile>( lexer) || TryPeek< keyword_mutable>( lexer) || TryPeek< keyword_register>( lexer) || TryPeek< keyword_template>( lexer) ) { node_t* node = lexer.GetNext(); modifiers.items.push_back( node); modifiers.end = node->end; } else if ( node_t* internal=TryGetInternal( lexer, context)) modifiers.items.push_back( internal); else break; } } node_t* GetTypename( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; node_t* node = tryget_typename( lexer, context); if ( !node) { throw parser::error_t( lexer, "Expecting typename"); } debug0 << "found typename " << *node << "\nnext token is " << *lexer.PeekNext() << "\n"; return node; } internal_t* TryGetInternal( lexer_t& lexer, context_t& context) /* Reads compiler-specific stuff. This is for gcc's __attribute__(...) etc */ { debug_TRACE_PRETTY; identifier_t* id = TryPeek< identifier_t>( lexer); if ( id && ( *id=="__attribute__" || *id=="__inline__" || *id=="__extension__" || *id=="__restrict" || *id== "__restrict__" || *id=="__stdcall" || *id=="__asm" || *id=="__asm__" )) { lexer.Skip( id); lexer_mark_t lexmark( lexer); internal_t* internal = new internal_t; internal->begin = id->begin; internal->end = id->end; internal->identifier = id; debug0 << "Read internal id `" << *id << "'\n"; context_t context2( context); context2.detailedparse = false; if ( *id=="__asm" || *id=="__asm__") { for(;;) { node_t* n = lexer.PeekNext(); if ( !n) break; if ( typeid( *n)==typeid( keyword_OPENROUND)) break; if ( !dynamic_cast< identifier_t*>( n) && !dynamic_cast< keyword_t*>( n)) break; internal->extra0.items.push_back( n); lexer.Skip( n); } } internal->extra = TryGetBlock( lexer, context2, typeid( keyword_OPENROUND)); if ( internal->extra) internal->end = internal->extra->end; else lexmark.Backtrack(); /* couldn't find (...), so restore to after the */ debug0 << "Read internal thingy: `" << *internal << "'\n"; return internal; } else return NULL; } function_parameters_t* GetFnParams( lexer_t& lexer, context_t& context); function_parameters_t* TryGetFnParams( lexer_t& lexer, context_t& context); baseclasses_t* GetBaseClasses( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; baseclasses_t* bcs = new baseclasses_t; for ( keyword_t* c = TryGet< keyword_COLON>( lexer); c; c = TryGet< keyword_COMMA>( lexer)) { baseclass_t* bc = new baseclass_t; bc->pre = c; while ( TryPeek< keyword_public>( lexer) || TryPeek< keyword_private>( lexer) || TryPeek< keyword_protected>( lexer) || TryPeek< keyword_virtual>( lexer)) { bc->inheritance.push_back( Get< keyword_t>( lexer)); } bc->name = get_name( lexer, context); bcs->items.push_back( bc); } return bcs; } function_parameters_t* GetFnParams( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; function_parameters_t* fnparams = TryGetFnParams( lexer, context); if ( !fnparams) throw parser::error_t( lexer, "Expecting fn params"); return fnparams; } function_parameters_t* TryGetFnParams( lexer_t& lexer, context_t& context0) { debug_TRACE_PRETTY; debug0 << "TryGetFnParams called\n"; lexer_mark_t lexmark( lexer); context_t context( context0); context.location = context_t::FNPARAMS; function_parameters_t* fnparams = new function_parameters_t; fnparams->openround = TryGet< keyword_OPENROUND>( lexer); if ( !fnparams->openround) { lexmark.Backtrack(); return NULL; } fnparams->node_t::begin = fnparams->openround->begin; for(;;) { debug0 << "Looking for param\n"; if ( keyword_DOTDOTDOT* ddd=TryGet< keyword_DOTDOTDOT>( lexer)) { fnparams->dotdotdot = ddd; fnparams->closeround = Get< keyword_CLOSEROUND>( lexer); fnparams->node_t::end = fnparams->closeround->end; break; } if ( keyword_CLOSEROUND* closeround = TryGet< keyword_CLOSEROUND>( lexer)) { fnparams->closeround = closeround; fnparams->node_t::end = closeround->end; break; } node_t* node = tryget_top_level_node( lexer, context); if ( !node) { lexmark.Backtrack(); return NULL; } debug0 << "Found fnparam " << *node << "\n"; /* tryget_top_level_node can return either a declarator_names_t or a declarator_terminator_t, depending on whether the declaration is C-syntax or new-style declaration syntax. */ declarator_terminator_t* declterm = NULL; if ( declarator_names_t* declnames = dynamic_cast< declarator_names_t*>( node)) { assert( declnames->items.size()==1); // `context' indicates that only single decls are allowed. declterm = declnames->items.front(); if ( declterm->terminator && typeid( *declterm->terminator)!=typeid( keyword_COMMA)) { lexmark.Backtrack(); return NULL; } /* terminator not `,' or , so can't be proper function para,. e.g. embedded function body, which will be handled by out expression parser instead when we return NULL. */ if ( declnames->prefix && declnames->prefix->ContainsType( typeid( keyword_virtual))) { ++fnparams->num_virtparams; } fnparams->params.push_back( declnames); } else // any other type of item can't be a function param. { lexmark.Backtrack(); return NULL; } } debug0 << "~GetFnParams(), num params=" << fnparams->params.size() << ", fnparams are:\n" << *fnparams << "\n"; return fnparams; } access_t* TryGetAccess( parser::lexer_t& lexer, const context_t& /*context*/) { debug_TRACE_PRETTY; keyword_t* k = NULL; if ( !k) k = TryGet< keyword_public>( lexer); if ( !k) k = TryGet< keyword_protected>( lexer); if ( !k) k = TryGet< keyword_private>( lexer); if ( !k) return NULL; access_t* access = new access_t; access->access = k; access->colon = Get< keyword_COLON>( lexer); access->begin = k->begin; access->end= lexer.GetPos(); return access; } } // end of anonymous namespace. namespace parser { declarator_left_t* TryGetDeclaratorLeft( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; declarator_left_t* dl = new declarator_left_t; dl->begin = lexer.GetPos(); dl->modifiers = new modifiers_t; SetModifiers( lexer, context, *dl->modifiers); dl->typenam = TryGet< keyword_typename>( lexer); SetModifiers( lexer, context, *dl->modifiers); keyword_class* kclas = TryPeek< keyword_class>( lexer); keyword_struct* struc = TryPeek< keyword_struct>( lexer); keyword_enum* enu = TryPeek< keyword_enum>( lexer); keyword_union* unio = TryPeek< keyword_union>( lexer); if ( kclas || struc) { const char* begin = lexer.GetPos(); lexer.GetNext(); keyword_t* class_or_struct; if ( kclas) class_or_struct = kclas; else class_or_struct = struc; name_t* name = tryget_name( lexer, context); template_specialisation_t* template_instantiation = TryGetTemplateSpec( lexer, context); baseclasses_t* baseclasses = GetBaseClasses( lexer, context); if ( TryPeek< keyword_OPENCURLY>( lexer)) { class_t* clas = new class_t; clas->begin = begin; clas->class_or_struct = class_or_struct; clas->name = name; clas->baseclasses = baseclasses; clas->template_instantiation = template_instantiation; clas->block = GetBlock( lexer, context, typeid( keyword_OPENCURLY)); clas->end = lexer.GetPos(); dl->name = clas; } else { class_fwd_t* classfwd = new class_fwd_t; classfwd->class_or_struct = class_or_struct; classfwd->name = name; classfwd->template_instantiation = template_instantiation; classfwd->begin = begin; classfwd->end = lexer.GetPos(); dl->name = classfwd; } } else if ( enu || unio) { lexer.GetNext(); identifier_t* name = TryGet< identifier_t>( lexer); template_specialisation_t* template_instantiation = TryGetTemplateSpec( lexer, context); context_t context2( context); context2.detailedparse = false; debug0 << "Looking for block after num/union\n"; if ( block_t* block = TryGetBlock( lexer, context2)) { enum_or_union_t* eu = new enum_or_union_t; if ( enu) eu->enum_or_union = enu; else eu->enum_or_union = unio; eu->begin = eu->enum_or_union->begin; eu->name = name; eu->template_instantiation = template_instantiation; eu->block = block; eu->end = block->end; dl->name = eu; debug0 << "enum/union: begin=" << (const void*)eu->begin << ", " << (const void*)eu->end << ": " << *eu << "\n"; } else { enum_or_union_fwd_t* euf = new enum_or_union_fwd_t; if ( enu) euf->enum_or_union_t = enu; else euf->enum_or_union_t = unio; euf->name = name; euf->template_instantiation = template_instantiation; euf->begin = euf->enum_or_union_t->begin; if ( template_instantiation) euf->end = template_instantiation->end; else if ( name) euf->end = name->end; else euf->end = euf->enum_or_union_t->end; dl->name = euf; } } else { lexer_mark_t lexmark( lexer); dl->name = tryget_typename( lexer, context); if ( !dl->name) { lexmark.Backtrack(); return NULL; } debug0 <name=" << *dl->name << "\n"; SetModifiers( lexer, context, *dl->modifiers); /* hacky incorrect bit comming up: if name looks like a constructor or destructor, we return an empty declarator_left_t - constructors have no return type. The test for a constructor is wrong - eg if a namespace has a member with same name as namespace; hopefully this won't happen too much. tryget_top_level_node tries looking for return-less fns, so this behaviour is probably not required here.*/ const name_t* name = dynamic_cast< const name_t*>( dl->name); if ( name && name->elements.size() >= 2) { if ( dynamic_cast < const name_element_destructor_t*>( name->elements.back())) { debug0 << "destructor - not returning declleft\n"; lexmark.Backtrack(); dl->name = NULL; return dl; } const name_element_normal_t* a = dynamic_cast< const name_element_normal_t*>( name->elements[ name->elements.size()-2]); const name_element_normal_t* b = dynamic_cast< const name_element_normal_t*>( name->elements[ name->elements.size()-1]); if ( a && b) { if ( *a->identifier == *b->identifier) { lexmark.Backtrack(); dl->name = NULL; debug0 << "backtracking - declleft us c'tr: " << *dl << "\n"; return dl; } } } } dl->trailing_internal = TryGetInternal( lexer, context); if ( dl->trailing_internal) { debug0 << "dl->trailing_internal=" << *dl->trailing_internal << "\n"; } debug0 << debug_PLACE << "found declleft: " << dl->output_tech_tostring() << "\n"; debug0 << debug_PLACE << "found declleft: " << dl->output_complete_tostring() << "\n"; return dl; } declarator_left_t* get_declarator_left( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; declarator_left_t* declleft = TryGetDeclaratorLeft( lexer, context); if ( !declleft) throw parser::error_t( lexer, "Expecting declaratorleft"); return declleft; } node_t* tryget_typename( lexer_t& lexer, context_t& context) { debug0 << "tryget_typename, lexertoken=" << *lexer.PeekNext() <<"\n"; debug_TRACE_PRETTY; node_t* ret = NULL; // look for any combination of long, short, signed etc. multiple_nodes_t* multiple = NULL; for(;;) { node_t* n = lexer.PeekNext(); const std::type_info& t = typeid( *n); if ( t==typeid( keyword_long) || t==typeid( keyword_short) || t==typeid( keyword_signed) || t==typeid( keyword_unsigned) || t==typeid( keyword_double) || t==typeid( keyword_float) || t==typeid( keyword_int) || t==typeid( keyword_short) || t==typeid( keyword_char) || *n=="__signed" /* for netbsd/gcc's headers*/ ) { if ( ret) { // this is second or third or... match if ( !multiple) { // this is second match multiple = new multiple_nodes_t; multiple->begin = ret->begin; multiple->items.push_back( ret); ret = multiple; } multiple->items.push_back( lexer.GetNext()); multiple->end = lexer.GetPos(); } else ret = lexer.GetNext(); } else break; } if ( !ret) ret = TryGet< keyword_bool>( lexer); if ( !ret) ret = TryGet< keyword_void>( lexer); if ( !ret) { if ( keyword_struct* struc=TryGet< keyword_struct>( lexer)) { struct_name_t* structname=new struct_name_t; structname->struc = struc; structname->name = TryGet< identifier_t>( lexer); structname->block = TryGetBlock( lexer, context); ret = structname; } } // user-defined type if ( !ret) { debug0 << "tryget_typename looking for user type\n"; keyword_typename* typenam=TryGet< keyword_typename>( lexer); name_t* name = tryget_name( lexer, context); debug0 << "tryget_typename: typenam=" << typenam << "\n"; debug0 << "tryget_typename: name=" << name << "\n"; if ( name) { if ( typenam) { debug0 << "found typename name: " << *typenam <<" , " << *name << "\n"; multiple_nodes_t* mul = new multiple_nodes_t; mul->begin = typenam->begin; mul->items.push_back( typenam); mul->items.push_back( name); mul->end = name->end; ret = mul; } else { ret = name; } } } //if ( ret) debug0 << "tryget_typename returning " << *ret << "\n"; //else debug0 << "tryget_typename returning null\n"; return ret; } name_t* parser::tryget_name( lexer_t& lexer, context_t& context) { //static int hp1=HierProf_InitBlock( "tryget_name 1"); //HierProf_StartClock1( hp1); debug_TRACE_PRETTY; debug0 << "tryget_name, next is " << *lexer.PeekNext() << "\n"; lexer_mark_t lexmark( lexer); const char* begin = lexer.GetPos(); name_t* name = NULL; /*/ Look for `__extension__(...)', and treat it as a name - some gcc headers require this. */ if ( identifier_t* id = TryPeek< identifier_t>( lexer)) { debug0 << debug_PLACE << "read identifier_t\n"; lexer.Skip( id); if ( *id=="__extension__" && TryPeek< keyword_OPENROUND>( lexer)) { lexmark.Backtrack(); internal_t* internal = TryGetInternal( lexer, context); assert( internal); name_t* name0 = new name_t; // create a hacky pseudo identifier: identifier_t* newid = new identifier_t; newid->begin = internal->begin; newid->end = internal->end; name_element_normal_t* nameelementnormal = new name_element_normal_t; nameelementnormal->identifier = newid; name0->elements.push_back( nameelementnormal); name0->begin = newid->begin; name0->end = newid->end; //HierProf_StopClock1( hp1); return name0; } lexmark.Backtrack(); } bool dont_look_for_coloncolon = false; /* used for special cases where `::' isn't expected - at start of name, and after `template'. */ //HierProf_StopClock1( hp1); for(;;) { //HierProf_SCOPEDBLOCK( "tryget_name forloop"); debug0 << debug_PLACE << "parser::tryget_name, name=" << *name << "\n"; keyword_COLONCOLON* coloncolon = NULL; if ( !dont_look_for_coloncolon) { coloncolon = TryGet< keyword_COLONCOLON>( lexer); if ( !coloncolon && name && name->elements.size()!=0) break; } dont_look_for_coloncolon = false; //debug0 << "coloncolon* = " << ((void*)coloncolon) << "\n"; name_element_t* nameelement = NULL; bool finish = false; // finsh is set if a nameelement like `::operator =' or `::*' is found. if ( keyword_operator* operatio = TryGet< keyword_operator>( lexer)) { debug0 << debug_PLACE << "read operator `" << *operatio << "\n"; name_element_operator_t* nameelementoperator = new name_element_operator_t; nameelement = nameelementoperator; nameelementoperator->coloncolon = coloncolon; nameelementoperator->operatio = operatio; nameelementoperator->begin = operatio->begin; if ( keyword_OPENROUND* kor=TryGet< keyword_OPENROUND>( lexer)) { multiple_nodes_t* oc = new multiple_nodes_t; oc->items.push_back( kor); oc->items.push_back( Get< keyword_CLOSEROUND>( lexer)); nameelementoperator->operation = oc; } else if ( keyword_OPENSQUARE* kos=TryGet< keyword_OPENSQUARE>( lexer)) { multiple_nodes_t* oc = new multiple_nodes_t; oc->items.push_back( kos); oc->items.push_back( Get< keyword_CLOSESQUARE>( lexer)); nameelementoperator->operation = oc; } else { multiple_nodes_t* mul = new multiple_nodes_t; nameelementoperator->operation = mul; modifiers_t* modifiers = new modifiers_t; SetModifiers( lexer, context, *modifiers); mul->items.push_back( modifiers); if ( name_t* name0 = tryget_name( lexer, context)) { // for `operator ' mul->items.push_back( name0); } else { mul->items.push_back( Get< keyword_t>( lexer)); // will accept any keyword, eg 'operator int'... } if ( typeid( *mul->items.back())==typeid( keyword_delete) || typeid( *mul->items.back())==typeid( keyword_new)) { if ( TryPeek< keyword_OPENSQUARE>( lexer)) { mul->items.push_back( Get< keyword_OPENSQUARE>( lexer)); mul->items.push_back( Get< keyword_CLOSESQUARE>( lexer)); } } else for(;;) // accept any number of trailing `*' { if ( keyword_STAR* star = TryGet< keyword_STAR>( lexer)) mul->items.push_back( star); else if ( keyword_AMP* amp = TryGet< keyword_AMP>( lexer)) mul->items.push_back( amp); else break; //std::cerr << "read * or &. items are " << *mul << "\n"; } } if ( dynamic_cast< keyword_new*>( nameelementoperator->operation) || dynamic_cast< keyword_delete*>( nameelementoperator->operation) ) { // handle `operator new[]' or `operator delete[]' if ( keyword_OPENSQUARE* os = TryGet< keyword_OPENSQUARE>( lexer)) { multiple_nodes_t* n = new multiple_nodes_t; n->items.push_back( nameelementoperator->operation); n->items.push_back( os); n->items.push_back( Get< keyword_CLOSESQUARE>( lexer)); nameelementoperator->operation = n; } } nameelementoperator->end = lexer.GetPos(); finish = true; } else if ( name && name->elements.size()!=0 && TryPeek< keyword_template>( lexer)) { //std::cerr << "found tempalte\n"; keyword_template* templat = Get< keyword_template>( lexer); /* don't really understand this syntax. For now, we treat it as a name element that isn't followed by `::'*/ nameelement_template_t* nameelementtemplate = new nameelement_template_t; nameelementtemplate->coloncolon = coloncolon; nameelementtemplate->templat = templat; nameelementtemplate->begin = templat->begin; nameelementtemplate->end = templat->end; nameelement = nameelementtemplate; dont_look_for_coloncolon = true; } else if ( keyword_TILDE* tilde = TryGet< keyword_TILDE>( lexer)) { name_t* name = tryget_name( lexer, context); if ( !name) { lexmark.Backtrack(); return NULL; } //std::cerr << "nameelement is '~...'\n"; name_element_destructor_t* ned = new name_element_destructor_t; nameelement = ned; ned->coloncolon = coloncolon; ned->tilde = tilde; ned->name = name; ned->begin = tilde->begin; ned->end = ned->name->end; finish = true; } else if ( identifier_t* identifier = TryGet< identifier_t>( lexer)) { debug0 << "Found identifier " << *identifier << "\n"; name_element_normal_t* nameelementnormal = new name_element_normal_t; nameelement = nameelementnormal; nameelementnormal->coloncolon = coloncolon; nameelementnormal->identifier = identifier; nameelementnormal->begin = (coloncolon) ? coloncolon->begin : identifier->begin; nameelementnormal->end = (nameelementnormal->templatespec) ? nameelementnormal->templatespec->end : identifier->end; /*debug0 << "making nameelementnormal, identifier=`" << *identifier << "', nen= " << nameelementnormal->end-nameelementnormal->begin << " `" << *nameelementnormal << "'\n"; */ } else { //std::cerr << "Not operator, not identifier\n"; if ( name && name->elements.size()) { if ( keyword_STAR* star=TryGet< keyword_STAR>( lexer)) { name_element_member_ptr_t* nemp = new name_element_member_ptr_t; nameelement = nemp; nemp->coloncolon = coloncolon; nemp->star = star; nemp->begin = star->begin; nemp->end = star->end; finish = true; } } } if ( nameelement) { nameelement->templatespec = TryGetTemplateSpec( lexer, context); if ( !name) { name = new name_t; name->begin = begin; name->namespac = context.parentnamespace; } name->elements.push_back( nameelement); if ( finish) break; } else { if ( name && name->elements.size()) throw parser::error_t( lexer, "Expecting identifier or `*' after `::'"); break; } } if ( name && name->elements.size()) { name->end = lexer.GetPos(); if ( NULL==name->elements.front()->begin) { debug0 << "found name, name->elements.front()->begin==0, *name is " << *name << "\n"; } debug0 << "found name " << *name <<"\n"; return name; } else { //debug << "found no name\n"; delete name; return NULL; } } node_t* GetDeclaratorNames( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; node_t* ret = tryget_declarator_names( lexer, context); if ( !ret) throw parser::error_t( lexer, "Expecting declarator_names_t"); return ret; } } declarator_names_t* TryGetReturnlessFn( lexer_t& lexer, context_t& context) /* Looks for a function with no return type - e.g. constructor. C++ really requires name lookup to do this - to know whether a name is a known type or a known class name. */ { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); declarator_names_t* declnames = tryget_declarator_names_internal( lexer, context, false); if ( !declnames || declnames->items.size() != 1 || !declnames->items.back()->declarator->is_simple_function()) { lexmark.Backtrack(); return NULL; } return declnames; } parser::compound_t* GetCompound( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); compound_t* compound = new compound_t; if ( !context.detailedparse) { debug0 << "GetCompound, calling getblock\n"; block_t* block = GetBlock( lexer, context); compound->open = dynamic_cast< keyword_OPENCURLY*>( block->open); compound->items = block->items.items; compound->close = dynamic_cast< keyword_CLOSECURLY*>( block->close); assert( compound->open); assert( compound->close); compound->begin = block->begin; compound->end = block->end; delete block; return compound; } compound->open = Get< keyword_OPENCURLY>( lexer); compound->begin = compound->open->begin; compound->parent = context.parentnamespace; context_t context2( context); context2.parentnamespace = compound; for(;;) { compound->close = TryGet< keyword_CLOSECURLY>( lexer); if ( compound->close) break; node_t* node; node = get_top_level_node( lexer, context2); if ( typeid( *node)==typeid( endoffile_t)) { lexmark.Backtrack(); throw parser::error_t( lexer, "Unexpected EOF in compound block"); } compound->items.push_back( node); } compound->end = lexer.GetPos(); return compound; } parser::label_t* TryGetLabel( lexer_t& lexer, context_t& /*context*/) { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); identifier_t* identifier = TryGet< identifier_t>( lexer); if ( !identifier) return NULL; keyword_COLON* colon = TryGet< keyword_COLON>( lexer); if ( !colon) { lexmark.Backtrack(); return NULL; } /* have to qualify label_t so that it doesn't clash with definition in openbsd's /machine/types.h */ parser::label_t* label = new parser::label_t; label->begin = identifier->begin; label->identifier = identifier; label->colon = colon; label->end = colon->end; debug0 << "found label\n"; return label; } node_t* parser::tryget_top_level_node( parser::lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; node_t* item = NULL; debug0 << "get_top_level_node, pos is " << parser::error_t( lexer, "no error").what() << "\n"; internal_t* internalprefix = TryGetInternal( lexer, context); if ( internalprefix) { debug0 << "parser::tryget_top_level_node: found internal: " << *internalprefix << "\n"; return internalprefix; } debug_TRACE_LINE; keyword_extern* exter; string_t* strin; if ( TryGetMulti( lexer, exter, strin)) { debug_TRACE_LINE; linkage_t* linkage = new linkage_t; linkage->exter = exter; linkage->begin = exter->begin; linkage->linkagename = strin; linkage->parent = context.parentnamespace; linkage->opencurly = TryGet< keyword_OPENCURLY>( lexer); if ( linkage->opencurly) { // extern "C" {...} debug_TRACE_LINE; for(;;) { if ( keyword_CLOSECURLY* cc=TryGet< keyword_CLOSECURLY>( lexer)) { linkage->closecurly = cc; linkage->end = cc->end; break; } else if ( TryPeek< endoffile_t>( lexer)) throw parser::error_t( lexer, "Unexpected EOF inside linkage spec"); else linkage->items.push_back( get_top_level_node( lexer, context)); } } else { // `extern "C" void foo(); debug_TRACE_LINE; linkage->closecurly = NULL; linkage->items.push_back( get_top_level_node( lexer, context)); linkage->end = linkage->items.back()->end; } item = linkage; } else if ( const endoffile_t* e = TryGet< endoffile_t>( lexer)) { debug_TRACE_LINE; item = new endoffile_t( *e); } else if ( keyword_SEMICOLON* semicolon = TryGet< keyword_SEMICOLON>( lexer)) { debug_TRACE_LINE; item = semicolon; } else if ( keyword_throw* thro = TryGet< keyword_throw>( lexer)) { debug_TRACE_LINE; throw_expression_t* t = new throw_expression_t; t->thro = thro; if ( TryPeek< keyword_SEMICOLON>( lexer)) t->expression = NULL; else t->expression = get_expression( lexer, context); t->semicolon = Get< keyword_SEMICOLON>( lexer); t->begin = t->thro->begin; t->end = lexer.GetPos(); item = t; } else if ( keyword_delete* delet = TryGet< keyword_delete>( lexer)) { debug_TRACE_LINE; delete_t* d = new delete_t; d->delet = delet; d->squarebrackets = TryGetSquareBrackets( lexer, context); d->expression = get_expression( lexer, context); d->semicolon = Get< keyword_SEMICOLON>( lexer); d->begin = delet->begin; d->end = d->semicolon->end; item = d; } else if ( keyword_asm* as_k = TryGet< keyword_asm>( lexer)) { debug_TRACE_LINE; context_t context2( context); context2.detailedparse = false; debug0 << "found `asm'\n"; assembler_block_t* as = new assembler_block_t; as->begin = as_k->begin; as->as = as_k; as->items = GetBlock( lexer, context2, typeid( keyword_OPENROUND)); as->semicolon = Get< keyword_SEMICOLON>( lexer); as->end = as->semicolon->end; item = as; debug0 << "read asm: " << *as << "\n"; } else if ( keyword_catch* catc = TryGet< keyword_catch>( lexer)) { debug_TRACE_LINE; catch_t* c = new catch_t; c->catc = catc; c->openround = Get< keyword_OPENROUND>( lexer); c->param = TryGet< keyword_DOTDOTDOT>( lexer); if ( !c->param) c->param = get_declarator_name( lexer, context); c->closeround = Get< keyword_CLOSEROUND>( lexer); c->block = get_top_level_node( lexer, context); c->begin = catc->begin; c->end = c->block->end; item = c; } else if ( keyword_try* tr = TryGet< keyword_try>( lexer)) { debug_TRACE_LINE; try_t* t = new try_t; t->tr = tr; t->block = get_top_level_node( lexer, context); t->begin = tr->begin; t->end = t->block->end; item = t; } else if ( keyword_for* fo = TryGet< keyword_for>( lexer)) { debug_TRACE_LINE; context_t context2( context); context2.location = context_t::NORMAL; for_loop_t* forloop = new for_loop_t; forloop->fo = fo; forloop->open = Get< keyword_OPENROUND>( lexer); forloop->expr1 = get_for_loop_initstatement( lexer, context2); forloop->expr2 = tryget_expression( lexer, context2); forloop->semicolon2 = Get< keyword_SEMICOLON>(lexer); forloop->expr3 = tryget_expression( lexer, context2); forloop->close = Get< keyword_CLOSEROUND>( lexer); debug0 << "forloop parser: calling get_top_level_node for contents\n"; forloop->contents = get_top_level_node( lexer, context2); debug0 << "fooloop, contents is type " << typeid( *forloop->contents).name() << "\n"; forloop->begin = fo->begin; forloop->end = lexer.GetPos(); item = forloop; } else if ( keyword_if* kwd_if = TryGet< keyword_if>( lexer)) { debug_TRACE_LINE; if_t* i = new if_t; i->begin = kwd_if->begin; i->kwd_if = kwd_if; i->open = Get< keyword_OPENROUND>( lexer); i->expression = get_if_expression( lexer, context); i->close = Get< keyword_CLOSEROUND>( lexer); i->statement = get_top_level_node( lexer, context); if ( keyword_else* els = TryGet< keyword_else>( lexer)) { i->els = els; i->else_statement = get_top_level_node( lexer, context); } else { i->els = NULL; i->else_statement = NULL; } i->end = lexer.GetPos(); item = i; } else if ( comment_or_hash_t* commentorhash = TryGet< comment_or_hash_t>( lexer)) { debug_TRACE_LINE; item = commentorhash; } else if ( keyword_using* using_keyword=TryPeek< keyword_using>( lexer)) { debug_TRACE_LINE; lexer.GetNext(); using_t* usin = new using_t; usin->usin = using_keyword; usin->namespac = TryGet< keyword_namespace>( lexer); usin->name = get_name( lexer, context); usin->semicolon = Get< keyword_SEMICOLON>( lexer); usin->begin = using_keyword->begin; usin->end = lexer.GetPos(); item = usin; } else if ( keyword_return* retur=TryGet< keyword_return>( lexer)) { debug_TRACE_LINE; return_t* ret = new return_t; ret->begin = retur->begin; ret->retur = retur; ret->expression = tryget_expression( lexer, context); ret->semicolon = Get< keyword_SEMICOLON>( lexer); ret->end = ret->semicolon->end; item = ret; } else if ( keyword_while* whil=TryGet< keyword_while>( lexer)) { debug_TRACE_LINE; while_t* ret = new while_t; ret->whil = whil; ret->expression = get_expression( lexer, context); ret->statement = get_top_level_node( lexer, context); ret->begin = ret->whil->begin; ret->end = ret->statement->end; item = ret; } else if ( access_t* access = TryGetAccess( lexer, context)) { debug_TRACE_LINE; item = access; } else if ( keyword_namespace* namespac_keyword=TryGet< keyword_namespace>( lexer)) { debug_TRACE_LINE; debug0 << "Start of `namespace'\n"; namespace_t* namespac = NULL; namespace_eq_t* namespaceeq = NULL; identifier_t* name = TryGet< identifier_t>( lexer); if ( name) { if ( keyword_EQ* eq=TryGet< keyword_EQ>( lexer)) { debug_TRACE_LINE; namespaceeq = new namespace_eq_t; item = namespaceeq; namespaceeq->namespac = namespac_keyword; namespaceeq->name = name; namespaceeq->eq = eq; namespaceeq->namespacerhs = get_name( lexer, context); namespaceeq->semicolon = Get< keyword_SEMICOLON>( lexer); namespaceeq->begin = name->begin; namespaceeq->end = namespaceeq->semicolon->end; item = namespaceeq; } } if ( !namespaceeq) { debug_TRACE_LINE; namespac = new namespace_t; namespac->begin = namespac_keyword->begin; namespac->parent = context.parentnamespace; item = namespac; namespac->namespac = namespac_keyword; namespac->leafname = name; namespac->opencurly = Get< keyword_OPENCURLY>( lexer); context_t context2( context); context2.parentnamespace = namespac; for(;;) { debug_TRACE_LINE; if ( keyword_CLOSECURLY* closecurly = TryGet< keyword_CLOSECURLY>( lexer)) { namespac->closecurly = closecurly; namespac->end = closecurly->end; item = namespac; break; } else if ( TryPeek< endoffile_t>( lexer)) { debug_TRACE_LINE; throw parser::error_t( lexer, "End of file within `namespace {...}'"); } else { debug_TRACE_LINE; debug0 << "Looking for top-level item in namespace, " << namespac->items.size() << " within namespace, lexline=" << lexer.GetLineNumber() << "\n"; namespac->items.push_back( get_top_level_node( lexer, context2)); debug0 << "Found item: " << *namespac->items.back() << "\n"; } } } } else if ( keyword_switch* switc=TryGet< keyword_switch>( lexer)) { debug_TRACE_LINE; switch_t* s = new switch_t; s->begin = switc->begin; s->switc = switc; s->expression = get_expression( lexer, context); s->open = Get< keyword_OPENCURLY>( lexer); for(;;) { if ( keyword_case* cas = TryGet< keyword_case>( lexer)) { case_t* c = new case_t; c->cas = cas; c->expression = get_expression( lexer, context); c->colon = Get< keyword_COLON>( lexer); s->cases.push_back( c); } else if ( keyword_default* defaul = TryGet< keyword_default>( lexer)) { case_default_t* d = new case_default_t; d->defaul = defaul; d->colon = Get< keyword_COLON>( lexer); s->cases.push_back( d); } else if ( keyword_CLOSECURLY* close = TryGet< keyword_CLOSECURLY>( lexer)) { s->close = close; break; } else { if ( s->cases.size()==0) { case_initial_t* c = new case_initial_t; s->cases.push_back( c); } node_t* n = get_top_level_node( lexer, context); s->cases.back()->statements.push_back( n); } } s->end = lexer.GetPos(); item = s; } else if ( keyword_typedef* typedef_keyword = TryGet< keyword_typedef>( lexer)) { debug_TRACE_LINE; typedef_t* typede = new typedef_t; typede->begin = typedef_keyword->begin; typede->typede = typedef_keyword; typede->declnames = GetDeclaratorNames( lexer, context); typede->end = typede->declnames->end; item = typede; } else if ( keyword_do* kd = TryGet< keyword_do>( lexer)) { debug_TRACE_LINE; do_t* d = new do_t; d->begin = kd->begin; d->d = kd; d->statement = get_top_level_node( lexer, context); d->whil = Get< keyword_while>( lexer); d->expression = get_expression( lexer, context); d->semicolon = Get< keyword_SEMICOLON>( lexer); d->end = lexer.GetPos(); item = d; } else if ( TryPeek< keyword_OPENCURLY>( lexer)) { debug_TRACE_LINE; debug0 << "gettoplevelitem found open curly\n"; if ( !context.detailedparse) { debug0 << "looking for block, 'cos not detail3d parsez\n"; item = GetBlock( lexer, context, typeid( keyword_OPENCURLY)); debug0 << "found block, 'cos not detail3d parsez\n"; } else { debug0 << "looking for compound, 'cos detailed parse\n"; item = GetCompound( lexer, context); } } else if ( declarator_names_t* declnames_newsyntax = tryget_declarator_names_newsyntax( lexer, context)) { debug_TRACE_LINE; item = declnames_newsyntax; } else if ( declarator_names_t* declnames = tryget_declarator_names( lexer, context)) { debug_TRACE_LINE; item = declnames; debug0 << "Found " << typeid( *item).name() << ": " << *item << "\n"; } else if ( node_t* declnames_returnlessfn = TryGetReturnlessFn( lexer, context)) { debug_TRACE_LINE; item = declnames_returnlessfn; } else if ( expression_terminator_t* expr = tryget_terminated_expression( lexer, context)) { debug_TRACE_LINE; item = expr; } else if ( template_t* templat = TryGetTemplate( lexer, context)) { debug_TRACE_LINE; template_node_t* templatenode = new template_node_t; templatenode->template_spec = templat; debug0 << "found templatenode `" << templat->output_compact_tostring() << "'\n"; templatenode->node = get_top_level_node( lexer, context); item = templatenode; templatenode->begin = templat->begin; templatenode->end = lexer.GetPos(); item = templatenode; } else if ( label_t* label = TryGetLabel( lexer, context)) { debug_TRACE_LINE; item = label; } else if ( keyword_AMPERSAND* ampersand = TryGet< keyword_AMPERSAND>( lexer)) { debug_TRACE_LINE; ampersand_node_t* ampersandnode = new ampersand_node_t; ampersandnode->ampersand = ampersand; ampersandnode->name = Get< identifier_t>( lexer); ampersandnode->node = get_top_level_node( lexer, context); ampersandnode->begin = ampersand->begin; ampersandnode->end = lexer.GetPos(); item = ampersandnode; } else { debug_TRACE_LINE; item = NULL; return item; } debug_TRACE_LINE; if ( !item->begin || !item->end) debug0 << typeid( *item).name() << "\n"; if ( !item->begin) std::cerr << typeid( *item).name() << "\n"; assert( item->begin); if ( !item->end) std::cerr << typeid( *item).name() << "\n"; assert( item->end); return item; } node_t* parser::get_top_level_node( parser::lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; node_t* n = tryget_top_level_node( lexer, context); if ( !n) { /*debug << "context is: location=" << context.location << ", support_embedded_functions_in_expressions=" << context.support_embedded_functions_in_expressions << "\n";*/ throw parser::error_t( lexer, "Unrecognised top-level item"); } debug0 << "Found top level item `" << *n << "'\n"; debug0 << "get_top_level_node succeeded. failed was:\n" << parser::error_t( lexer, "dummy error").what() << "\n"; lexer.ClearFailed(); debug0 << "get_top_level_node succeeded. failed now:\n" << parser::error_t( lexer, "dummy error").what() << "\n"; return n; } namespace { void Erase( unsigned int length) { debug_TRACE_PRETTY; {for ( unsigned int i=0; ifilename = lexer.GetFilename(); context_t context; context.detailedparse = detailedparse; context.parentnamespace = compunit; context.support_embedded_functions_in_expressions = support_embedded_functions_in_expressions; context.support_new_declsyntax = support_new_declsyntax; context.caller_dispatch = caller_dispatch; const char* oldlexerpos = lexer.GetPos(); (void) verbose; for(;;) { node_t* item = get_top_level_node( lexer, context); if ( dynamic_cast< const endoffile_t*>( item)) break; assert( item); compunit->append_item( item); if ( lexer.GetPos() <= oldlexerpos) throw std::logic_error( "internal_t error - lexer position not progressing"); oldlexerpos = lexer.GetPos(); } return *compunit; } void SetDefaultValueForDeclTerm( declarator_terminator_t* declterm, lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; debug0 << "SetDefaultValueForDeclTerm, context=" << context << "\n"; if ( keyword_EQ* eq=TryGet< keyword_EQ>( lexer)) { debug0 << "SetDefaultValueForDeclTerm: found `='\n"; declterm->defaultvalue = new default_value_t; declterm->defaultvalue->eq = eq; if ( TryPeek< keyword_OPENCURLY>( lexer)) { context_t context2( context); context2.detailedparse = false; declterm->defaultvalue->value = GetBlock( lexer, context2, typeid( keyword_OPENCURLY)); } else declterm->defaultvalue->value = get_expression( lexer, context); } } name_t* parser::get_name( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; name_t* name = tryget_name( lexer, context); if ( !name) throw parser::error_t( lexer, "Expecting name"); return name; } bool SetTerminatorForDeclTerm( declarator_terminator_t* declterm, lexer_t& lexer, context_t& context) // returns false if fail. { debug_TRACE_PRETTY; declterm->end = lexer.GetPos(); debug0 << "SetTerminatorForDeclTerm: next node is " << *lexer.PeekNext() << "\n"; if ( keyword_COMMA* comma=TryGet< keyword_COMMA>( lexer)) { declterm->terminator = comma; // not ok if a radical syntax, but we don't know this here. declterm->end = comma->end; } else if ( TryPeek< keyword_CLOSEROUND>( lexer) || TryPeek< keyword_DOTDOTDOT>( lexer)) { /* variadic functin params can look like (int x ...), as well as (int x, ...).*/ if ( context.location==context_t::NORMAL) return false; // not a terminator. if ( context.location==context_t::FNPARAMS) return true; // a terminator. } else if ( keyword_SEMICOLON* semicolon = TryGet< keyword_SEMICOLON>( lexer)) { if ( context.location==context_t::NORMAL) { declterm->terminator = semicolon; declterm->end = semicolon->end; } else return false; } else if ( TryPeek< keyword_GT>( lexer)) { if ( context.location==context_t::TEMPLATESPEC) { declterm->terminator = NULL; declterm->end = lexer.GetPos(); return true; } else return false; } else { debug0 << "terminator can only be for a function body\n"; function_t* fn = declterm->declarator->is_simple_function(); if ( !fn) return false; context_t context2( context); context2.parentnamespace = fn; fnbody_t* fnbody = new fnbody_t; debug0 << "looking for fn inits etc\n"; debug0 << parser::error_t( lexer, "pos is:").what(); if ( keyword_COLON* colon=TryGet< keyword_COLON>( lexer)) { fnbody->initialisers = new multiple_nodes_t; fnbody->initialisers->items.push_back( colon); for(;;) { if ( TryPeek< keyword_OPENCURLY>( lexer)) break; else if ( TryPeek< endoffile_t>( lexer)) throw parser::error_t( lexer, "EOF in middle of ctr initionalisation"); else fnbody->initialisers->items.push_back( lexer.GetNext()); } } else if ( node_t* internal=TryGetInternal( lexer, context)) { debug0 << "found internal after fn parrams:" << *internal << "\n"; fnbody->initialisers = new multiple_nodes_t; fnbody->initialisers->items.push_back( internal); fnbody->initialisers->items.push_back( Get< keyword_SEMICOLON>( lexer)); fnbody->end = lexer.GetPos(); declterm->terminator = fnbody; declterm->end = declterm->terminator->end; return true; /* This is a hack to deal with things like u_int16_t bswap16(u_int16_t) __asm__("__bswap16"); which occurs in netbsd's /usr/include/machine/byte_swap.h . See test64. */ } if ( TryPeek< keyword_OPENCURLY>( lexer)) { fnbody->declterm = declterm; fnbody->body = GetCompound( lexer, context2); fnbody->end = fnbody->body->end; declterm->terminator = fnbody; declterm->end = declterm->terminator->end; } else { return false; } } return true; } namespace { declaratorprefix_t* get_declaratorprefix( lexer_t& lexer, context_t& /*context*/) { declaratorprefix_t* ret = NULL; for(;;) { if ( TryPeek< keyword_inline>( lexer) || TryPeek< keyword_virtual>( lexer) || TryPeek< keyword_static>( lexer) || TryPeek< keyword_friend>( lexer) || TryPeek< keyword_explicit>( lexer) || TryPeek< keyword_extern>( lexer) ) { debug0 << "read prefix item " << *lexer.PeekNext() << "\n"; if ( !ret) ret = new declaratorprefix_t; ret->items.items.push_back( lexer.GetNext()); if ( typeid( *ret->items.items.back()) == typeid( keyword_virtual)) { debug0 << "Found `virtual prefix'\n"; } } else { break; } } return ret; } } declarator_names_t* parser::tryget_declarator_names_internal( lexer_t& lexer, context_t& context, bool left_type) { debug_TRACE_PRETTY; debug0 << "tryget_declarator_names_internal, context=" << context << "\n"; lexer_mark_t lexmark( lexer); declarator_names_t* decls = new declarator_names_t; decls->begin = lexer.GetPos(); decls->prefix = get_declaratorprefix( lexer, context); if ( left_type) { decls->declleft = TryGetDeclaratorLeft( lexer, context); if ( !decls->declleft) { lexmark.Backtrack(); delete decls->prefix; delete decls; return NULL; } debug0 << "declleft is " << *decls->declleft << "\n"; } else { decls->declleft = NULL; debug0 << "no declleft\n"; } debug0 << "after declleft, decls=" << *decls << "\n"; for(;;) { declarator_terminator_t* declterm = new declarator_terminator_t; declterm->declarator = tryget_declarator( lexer, context, decls->declleft, false); if ( declterm->declarator) { debug0 << "tryget_declarator retuned " << *declterm->declarator << "\n"; } else debug0 << "tryget_declarator retuned NULL\n"; if ( !declterm->declarator) { if ( !decls->declleft) { lexmark.Backtrack(); delete declterm; delete decls->prefix; delete decls; return NULL; } declterm->declarator = decls->declleft; debug0 << "found anonmous declarator " << *declterm << "\n"; } SetDefaultValueForDeclTerm( declterm, lexer, context); decls->items.push_back( declterm); if ( !SetTerminatorForDeclTerm( declterm, lexer, context)) { debug0 << "SetTerminatorForDeclTerm failed\n"; delete declterm; delete decls->prefix; delete decls; lexmark.Backtrack(); return NULL; } if ( declterm->terminator && typeid( *declterm->terminator)==typeid( keyword_COMMA) && context.location==context_t::NORMAL) continue; else break; } debug0 << "found declnames, size=" << decls->items.size() << ": " << *decls << "\n" << "tech: " << decls->output_tech_tostring() << "\n"; decls->end = lexer.GetPos(); { debug0 << "Found declnames: " << *decls << "\n"; if ( decls->items.size()==1) { debug0 << "declnames has one item, type " << typeid( *decls->items.front()->declarator).name() << "\n"; if ( declarator_name_t* name = decls->items.front()->declarator->is_name()) { if ( name->name) { /* if we find a special cmm name, we replace it with a different name, so that cmm will parse the output a second time. see test73.*/ std::string n = name->name->output_compact_tostring(); bool special_name = true; if ( 0) ; else if ( n=="cmm_pragma_autoblocks_on") lexer.autoblocks = true; else if ( n=="cmm_pragma_autoblocks_off") lexer.autoblocks = false; else if ( n=="cmm_pragma_detailedparse_on") context.detailedparse = true; else if ( n=="cmm_pragma_detailedparse_off") context.detailedparse = false; else if ( n=="cmm_pragma_newdeclsyntax_on") context.support_new_declsyntax = true; else if ( n=="cmm_pragma_newdeclsyntax_off") context.support_embedded_functions_in_expressions = false; else if ( n=="cmm_pragma_embeddedfns_on") context.support_embedded_functions_in_expressions = true; else if ( n=="cmm_pragma_embeddedfns_off") context.support_new_declsyntax = false; else if ( n=="cmm_pragma_lexer_verbose_on") lexer.verbose = true; else if ( n=="cmm_pragma_lexer_verbose_off") lexer.verbose = false; else { special_name = false; } if ( special_name) { std::string newname = n + "_dummy"; name->name = name_t::MakeName( newname.c_str(), context); debug0 << "*** cmm pragma: " << n << " at " << lexer.GetFilename() << ":" << lexer.GetLineNumber() << "\n"; } } } } } return decls; } parser::declarator_names_t* parser::get_declarator_names_internal( parser::lexer_t& lexer, parser::context_t& context, bool left_type) { declarator_names_t* ret = parser::tryget_declarator_names_internal( lexer, context, left_type); if ( !ret) throw parser::error_t( lexer, "Expecting declarator"); return ret; } declarator_names_t* parser::tryget_declarator_names( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; return tryget_declarator_names_internal( lexer, context, true); } declarator_name_t* parser::tryget_declarator_name( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); declarator_name_t* declname = NULL; declarator_names_t* declnames = tryget_declarator_names_newsyntax( lexer, context); if ( !declnames) { context_t context2 = context; context2.location = context_t::FNPARAMS; declnames = tryget_declarator_names( lexer, context2); } if ( !declnames) return NULL; if ( declnames->items.size() != 1) { lexmark.Backtrack(); return NULL; } declarator_terminator_t* declterm = declnames->items.front(); declname = dynamic_cast< declarator_name_t*>( declterm->declarator); if ( !declname) { declname = new declarator_name_t; declname->subtype = declterm->declarator; declname->name = NULL; //std::cerr << "Adding null name, namedecl is " << *declname << "\n"; //std::cerr << "decl is: " << *decl << "\n"; //std::cerr << "declname is: " << *declname << "\n"; //std::cerr << "\n"; } return declname; } declarator_name_t* parser::get_declarator_name( lexer_t& lexer, context_t& context) { debug_TRACE_PRETTY; declarator_name_t* ret = tryget_declarator_name( lexer, context); if ( !ret) throw parser::error_t( lexer, "Expecting declarator name"); return ret; } array_t* TryGetArray( lexer_t& lexer, const context_t& /*context*/) { debug_TRACE_PRETTY; if ( keyword_OPENSQUARE* opensquare = TryGet< keyword_OPENSQUARE>( lexer)) { /*std::cerr << "just found opensquare, decl=" << *decl << ", ret=" << *ret << "\n";*/ array_t* arraydecl = new array_t; arraydecl->open = opensquare; arraydecl->begin = opensquare->begin; for(;;) { if ( keyword_CLOSESQUARE* close=TryGet< keyword_CLOSESQUARE>( lexer)) { arraydecl->close = close; arraydecl->end = close->end; break; } else arraydecl->items.push_back( lexer.GetNext()); } return arraydecl; } else { return NULL; } } declarator_t* parser::get_declarator( lexer_t& lexer, context_t& context, declarator_t* subtype, bool must_be_anonymous) { debug_TRACE_PRETTY; declarator_t* decl = tryget_declarator( lexer, context, subtype, must_be_anonymous); if ( !decl) throw parser::error_t( lexer, "Expected declarator"); return decl; } declarator_t* parser::tryget_declarator( lexer_t& lexer, context_t& context, declarator_t* subtype, bool must_be_anonymous) { debug_TRACE_PRETTY; lexer_mark_t lexmark( lexer); debug0 << "get_declarator, token=`" << *lexer.PeekNext() << "'\n"; internal_t* leading_internal = TryGetInternal( lexer, context); if ( leading_internal) { debug0 << "parser::tryget_declarator: leading_internal=" << *leading_internal << "\n"; } declarator_t* ret = NULL; declarator_t* decl = NULL; /* ret is the innermost declarator.decl is outer-level declarator. ret is different from decl when bracketdeclarator is found, eg 'int (*foo)'. */ name_t* name = NULL; if ( 0) ; else if ( keyword_STAR* star = TryGet< keyword_STAR>( lexer)) { pointer_t* ptr = new pointer_t; ptr->modifiers = new modifiers_t; ptr->star = star; ptr->begin = star->begin; ptr->end = star->end; ptr->subtype = subtype; SetModifiers( lexer, context, *ptr->modifiers); ret = tryget_declarator( lexer, context, ptr, must_be_anonymous); if ( !ret) { lexmark.Backtrack(); return NULL; } decl = ptr; //std::cerr << "found ptr: " << *ptr << "\n"; } else if ( keyword_AMP* amp = TryGet< keyword_AMP>( lexer)) { reference_t* ref = new reference_t; ref->modifiers = new modifiers_t; ref->amp = amp; ref->begin = amp->begin; ref->end = amp->end; ref->subtype = subtype; SetModifiers( lexer, context, *ref->modifiers); ret = tryget_declarator( lexer, context, ref, must_be_anonymous); if ( !ret) { lexmark.Backtrack(); return NULL; } decl = ref; } else if ( keyword_OPENROUND* openround = TryGet< keyword_OPENROUND>( lexer)) { debug0 << "start of bracketdeclarator\n"; bracket_declarator_t* bracket = new bracket_declarator_t; decl = bracket; bracket->subtype = subtype; bracket->open = openround; bracket->begin = openround->begin; bracket->close = NULL; // in case call to get_declarator in next line tries to display it. ret = tryget_declarator( lexer, context, bracket, must_be_anonymous); /* we will return 'ret' - the innermost declarator - but further parsing is for decl. */ if ( !ret) { lexmark.Backtrack(); return NULL; } debug0 << "bracket declarator, sub declarator is " << typeid(*ret).name() << ", " << *ret << "\n"; bracket->close = TryGet< keyword_CLOSEROUND>( lexer); if ( !bracket->close) { lexmark.Backtrack(); return NULL; } bracket->end = bracket->close->end; } else if ( !must_be_anonymous && ( name = tryget_name( lexer, context))) { if ( dynamic_cast( name->elements.back())) { // member pointer. we should probably look for modifiers... debug0 << "Found member pointer\n"; member_pointer_t* memberptr = new member_pointer_t; memberptr->clas = name; memberptr->subtype = subtype; decl = memberptr; ret = tryget_declarator( lexer, context, memberptr, must_be_anonymous); if ( !ret) { lexmark.Backtrack(); return NULL; } } else { declarator_name_t* declname = new declarator_name_t; declname->subtype = subtype; decl = ret = declname; declname->name = name; declname->begin = declname->name->begin; declname->end = declname->name->end; } } else if ( TryPeek< keyword_OPENSQUARE>( lexer)) { // make anonymous declarator_name_t declarator_name_t* declname = new declarator_name_t; declname->subtype = subtype; decl = ret = declname; declname->name = NULL; declname->begin = lexer.GetPos(); declname->end = lexer.GetPos(); } else { } if ( keyword_OPENROUND* openround = TryPeek< keyword_OPENROUND>( lexer)) { // function or constructor debug0 << "function_t\n"; function_t* fn = new function_t; fn->parent = context.parentnamespace; fn->subtype = decl->subtype; fn->parameters = TryGetFnParams( lexer, context); if ( fn->parameters) { decl->subtype = fn; fn->begin = decl->begin; fn->end = fn->parameters->node_t::end; SetModifiers( lexer, context, fn->modifiers); if ( keyword_throw* thro = TryGet< keyword_throw>( lexer)) { fn->throwspec = new throwspec_t; fn->throwspec->thro = thro; // we don;t ever bother to properly parse throw specs. context_t context2( context); context2.detailedparse = false; fn->throwspec->block = GetBlock( lexer, context2, typeid( keyword_OPENROUND)); } fn->internal = TryGetInternal( lexer, context); if ( fn->internal) { debug0 << "parser::tryget_declarator: found fn->internal=" << *fn->internal << "\n"; } debug0 << "function_t: " << *fn << ", " << fn->output_tech_tostring() << "\ndecl=" << *decl << "\n" << "\nret=" << *ret << "\n" << "\n"; } else { if ( declarator_name_t* declname = dynamic_cast< declarator_name_t*>( decl)) { lexer.Skip( openround); /* see whether it is a contructor initialiser, ( params). note horrible hack treats ',' as operator. Saves reading separate fn params. */ context_t context2( context); context2.location = context_t::EXPRESSION; expression_t* expr = tryget_expression( lexer, context2); if ( expr) { keyword_CLOSEROUND* close = TryGet< keyword_CLOSEROUND>( lexer); if ( !close) { lexmark.Backtrack(); return NULL; } multiple_nodes_t* mn = new multiple_nodes_t; mn->items.push_back( openround); mn->items.push_back( expr); mn->items.push_back( close); declname->constructor_params = mn; } else { lexmark.Backtrack(); return NULL; } } else { lexmark.Backtrack(); return NULL; } } } else if ( keyword_COLON* colon = TryGet< keyword_COLON>( lexer)) { debug0 << "Found bitfield colon\n"; //number_t* numberofbits = TryGet< number_t>( lexer); expression_t* numberofbits = tryget_expression( lexer, context); if ( !numberofbits) { lexmark.Backtrack(); return NULL; } debug0 << "found bitfield with number of bits `" << *numberofbits << "'\n"; bitfield_t* bitfield = new bitfield_t; bitfield->numberofbits = numberofbits; if ( decl) { bitfield->subtype = decl->subtype; decl->subtype = bitfield; } else { // anonymous bitfield - came across these in freebsd 5.1 headers. bitfield->subtype = subtype; ret = bitfield; decl = bitfield; } bitfield->colon = colon; bitfield->begin = colon->begin; bitfield->end = lexer.GetPos(); debug0 << "bitfield is: " << *bitfield << "\n"; } while ( array_t* arraydecl = TryGetArray( lexer, context)) { arraydecl->subtype = decl->subtype; decl->subtype = arraydecl; decl = arraydecl; } if ( decl) { decl->leading_internal = leading_internal; decl->trailing_internal = TryGetInternal( lexer, context); if (decl->trailing_internal) { debug0 << "end of parser::tryget_declarator: Found trailing internal: " << *decl->trailing_internal << "\n"; } debug0 << "\nGetDeclarator returning " << typeid( *ret).name() << ", " << *ret << "\n"; debug0 << ret->output_tech_tostring(); debug0 << "\n"; if ( decl->trailing_internal) { debug0 << "end of parser::tryget_declarator: decl->trailing_internal=" << *decl->trailing_internal << "\n"; } return ret; } else { // end of declaration return subtype; } } declarator_names_t* parser::tryget_declarator_names_newsyntax( parser::lexer_t& lexer, context_t& context) /* new declaration syntax, similar to `radical alternative', page 46 of Design & Evolution of C++. So: int x; can be written: x: int; More impressively, void ( *signal( int sig, void (*func) ( int sig )) ) ( int sig ); - can be written: signal: ( sig: int, func:-> ( sig: int) void ) -> (sig:int) void; Should modify somehow to cope with goto labels - the syntax conflicts with them. */ { debug_TRACE_PRETTY; if ( !context.support_new_declsyntax) return NULL; name_t* name; keyword_COLON* colon; const char* begin = lexer.GetPos(); lexer_mark_t lexmark( lexer); debug0 << "TryGetDeclaratorName2 called\n"; declaratorprefix_t* prefix = get_declaratorprefix( lexer, context); if ( prefix) debug0 << debug_PLACE << "tryget_declarator_names_newsyntax: prefix is " << *prefix << "\n"; if ( !(name = tryget_name( lexer, context)) || !(colon = TryGet< keyword_COLON>( lexer))) { debug0 << "Couldn't match name :\n"; delete prefix; lexmark.Backtrack(); return NULL; } declarator_names_t* declnames = NULL; declarator_name_t* declname = new declarator_name_t; declname->begin = (name) ? name->begin : NULL; declname->name = name; for( declarator_t* decl=declname;;) { modifiers_t* modifiers = new modifiers_t; SetModifiers( lexer, context, *modifiers); debug0 << "Current: " << *declname << "\n"; if ( 0) ; else if ( array_t* arraydecl = TryGetArray( lexer, context)) { decl->subtype = arraydecl; decl = arraydecl; } else if ( keyword_ARROW* arrow = TryGet< keyword_ARROW>( lexer)) { // reuse pointer_t class. Would be better to have a new class. (void) arrow; // not actually used, because we use a fake `*' to represent this decl. pointer_t* ptr = new pointer_t; decl->subtype = ptr; ptr->modifiers = modifiers; keyword_STAR* star = new keyword_STAR; star->begin = "*"; star->end = star->begin+1; ptr->star = star; ptr->begin = star->begin; ptr->end = star->end; decl = ptr; } else if ( keyword_AMP* amp = TryGet< keyword_AMP>( lexer)) { // reuse pointer_t class. Would be better to have a new class. reference_t* ref = new reference_t; decl->subtype = ref; ref->modifiers = modifiers; ref->amp = amp; ref->begin = amp->begin; ref->end = amp->end; decl = ref; } else if ( TryPeek< keyword_OPENROUND>( lexer)) { // function function_t* fn = new function_t; if ( dynamic_cast< pointer_t*>( decl)) { /* have to insert bracket declarator so that the generated code is correct C++. */ bracket_declarator_t* bracketdecl = new bracket_declarator_t; bracketdecl->open = new keyword_OPENROUND; bracketdecl->open->set_text( "("); bracketdecl->close = new keyword_CLOSEROUND; bracketdecl->close->set_text( ")"); decl->subtype = bracketdecl; decl = bracketdecl; } decl->subtype = fn; fn->parameters = GetFnParams( lexer, context); SetModifiers( lexer, context, fn->modifiers); // const is before params. Is this good? fn->parent = context.parentnamespace; fn->begin = fn->parameters->begin; fn->end = fn->parameters->end; decl = fn; } else { declnames = new declarator_names_t; declnames->prefix = prefix; declnames->begin = begin; declnames->declleft = TryGetDeclaratorLeft( lexer, context); if ( !declnames->declleft) { delete declnames->prefix; delete declnames; lexmark.Backtrack(); return NULL; } declnames->declleft->modifiers = modifiers; declnames->declleft->is_from_radical_alternative_syntax = true; decl->subtype = declnames->declleft ; declarator_terminator_t* declterm = new declarator_terminator_t; declterm->declarator = ( declname->name) ? declname : declname->subtype; declnames->items.push_back( declterm); SetDefaultValueForDeclTerm( declterm, lexer, context); if ( !SetTerminatorForDeclTerm( declterm, lexer, context)) { delete declnames->prefix; delete declnames; lexmark.Backtrack(); return NULL; } declnames->end = declterm->end; assert( declnames->end); debug0 << "New style decl: " << *declnames << "\n"; return declnames; } } } bool parser::NamespacesEq( const name_t& lhs, const name_t& rhs) { debug_TRACE_PRETTY; //std::cerr << "parser::NamespacesEq called, for " << lhs <<" & " << rhs << "\n"; for ( int i=1; ; ++i) { const node_t* l = lhs.GetElement( i); const node_t* r = rhs.GetElement( i); if ( !l && !r) return true; // end of comparison if ( !l || !r) return false; // different namespace depth. if ( *l != *r) return false; // different namespace depth. } } void parser::add_suffix( name_t*& name, const char* suffix) { /* Would like to create a stringstream on heap, write to it, and set things up to point into it. (and leave deallocating it to some sort of garbage collection). But there seems to be a problem with VC6's stringstream, so we write to a local stringstream, and make a copy of its contents in the form of a string on the heap. */ debug_TRACE; std::stringstream tempstream0; outstream_t tempstream( tempstream0); name = new name_t( *name); name_element_normal_t* last = dynamic_cast< name_element_normal_t*>( name->elements.back()); if ( !last) throw std::runtime_error( "Can't make impl name - last name element is operator"); name_element_normal_t* newlast = new name_element_normal_t( *last); name->elements.back() = newlast; newlast->identifier->output_compact( tempstream); tempstream.out << suffix; identifier_t* newidentifier = new identifier_t; newlast->identifier = newidentifier; std::string* ss = new std::string( tempstream0.str()); newidentifier->begin = ss->c_str(); newidentifier->end = newidentifier->begin + strlen( newidentifier->begin); } parser::declarator_terminator_t* declarator_names_t::get_single_declterm() { assert( this->items.size() == 1); return this->items[0]; } parser::declarator_terminator_t* declarator_names_t::is_single_declterm() { if ( this->items.size() == 1) return this->items[0]; else return NULL; }