int cmm_pragma_autoblocks_off(); #include "../cmm/parser.h" #include "../cmm/exceptionstream.h" #include #include #include int cmm_pragma_autoblocks_on(); struct OutStream2 : Parser::OutStream OutStream2( std::ostream& out) : Parser::OutStream( out), hierprof_return( false), have_seen_hierprof_function( false), use_hierprof_macros( false) ; hierprof_return: bool; have_seen_hierprof_function: bool; /* If true, return statements are modified to use HierProf macros. */ use_hierprof_macros: bool; ; Output2_: ( retur: & const Parser::Return, out: & OutStream2) void if ( out.hierprof_return) // Modify output to contain HierProf macros. if ( out.use_hierprof_macros) if ( retur.expression) out.out << "HierProf_ReturnValue(( "; else out.out << "HierProf_ReturnVoid()"; ; // output any space/comments after the `return'. Parser::TempChange simplenode_output_main( out.simplenode_output_main, false); Output2( *retur.retur, out); if ( retur.expression) Output2( *retur.expression, out); out.out << "))"; // We ommit the trailing semicolon - causes problems with HierProf_ReturnValue(). Parser::TempChange< bool> simplenode_output_main( out.simplenode_output_main, false); Output2( *retur.semicolon, out); else out.out << "{ " << "HierProf__StopClock( HierProf_fnref, HierProf_Clock_GetTimeFreeze()); " ; retur.Output( out); out.out << "}"; else retur.Output( out); Output2_: ( declname: & const Parser::DeclaratorName, out: & OutStream2) void declname.Output( out); if ( out.have_seen_hierprof_function) return; if ( declname.name->elements.size()==0) return; const Parser::NameElementNormal* nen = dynamic_cast( declname.name->elements[0]); std::cerr << "outputing name " << *nen << "\n"; if ( nen && (0 == strncmp( nen->begin, "HierProf_", 9))) out.have_seen_hierprof_function = true; std::cerr << "Found first HierProf_ function - will translate all subsequent function bodies\n"; Output2_: ( fnbody: & const Parser::FnBody, out: & OutStream2) void name: ->Parser::DeclaratorName = fnbody.declterm->declarator->IsName(); if ( !name) // fn is anonymous, so we don't add profiling info. Parser::TempChange default_output( out.hierprof_return, false); fnbody.Output( out); return; assert( name->name->elements.size() > 0); const Parser::NameElementNormal* nen = dynamic_cast( name->name->elements[0]); if (nen) { std::cerr << "outputing function " << *nen << "\n"; if ( !out.have_seen_hierprof_function && (0 == strncmp( nen->begin, "HierProf_", 9))) out.have_seen_hierprof_function = true; std::cerr << "Found first HierProf_ function - will translate all subsequent functions\n"; /*if ( nen->begin[0]=='_') std::cerr << "name " << * nen << " ignored\n"; Parser::TempChange default_output( out.hierprof_return, false); fnbody.Output( out); return;*/ } if ( !out.have_seen_hierprof_function) fnbody.Output( out); return; std::cerr << "Outputing function " << *nen << "\n"; /* output beginning of function body - any constructor initialisers, and the opening '{'. */ if ( fnbody.initialisers) Output2( *fnbody.initialisers, out); if (out.use_hierprof_macros) { Parser::TempChange no_extra( out.simplenode_output_extra, false); Parser::TempChange no_space( out.simplenode_output_space, false); Output2( *fnbody.body->open, out); } out.out << "HierProf_FnStart( \"" << name->Output2StringCompact( out) << "\")"; // now output space and any comments/#lines after the opening curly brace. { Parser::TempChange no_main( out.simplenode_output_main, false); Output2( *fnbody.body->open, out); } else out.out << "{ " << "static HierProf_ref_type HierProf_fnref=0; " << "if ( HierProf_fnref==0) HierProf_fnref=HierProf__InitBlock( \"" << name->Output2StringCompact( out) << "\"); " << "HierProf__StartClock( HierProf_fnref, HierProf_Clock_GetTimeFreeze()); " ; Output2( *fnbody.body->open, out); /* Output function body. We modify out so that any `return [];' in the function body will be converted to use HierProf_Return. */ Parser::TempChange hierprof_return( out.hierprof_return, true); for ( Parser::Compound::items_t::iterator it=fnbody.body->items.begin(); it!=fnbody.body->items.end(); ++it) Output2( **it, out); // Output end of function. Parser::DeclaratorLeft* declleft = fnbody.declterm->GetDeclaratorLeft(); // If declleft is `void', then we know to use HierProf_VoidFnStop etc. if ( declleft && declleft->name && typeid( *declleft->name)!=typeid( Parser::Keyword_void)) if (out.use_hierprof_macros) out.out << "HierProf_NonVoidFnStop()"; else out.out << "}"; else if (out.use_hierprof_macros) out.out << "HierProf_VoidFnStop()"; else out.out << "} HierProf__StopClock( HierProf_fnref, HierProf_Clock_GetTimeFreeze());"; // and now the closing '}': Output2( *fnbody.body->close, out); namespace usage: () void std::cout << "Params:\n" " -hierprof \n" " Adds calls to HierProf to specified source.\n" " -no-c++\n" " Parses as C, not C++.\n" " -immediate\n" " Transforms all functions, without waiting for\n" " first HierProf_ function to be seen\n" "\n"; main: ( argc: int, argv: ->->char) int try bool no_cplusplus = false; bool immediate = false; if ( argc==0) usage(); for ( int arg=1; arg=argc) throw std::runtime_error( "need 2 params after -hierprof"); infilename: std::string = argv[ arg+1]; outfilename: std::string = argv[ arg+2]; arg+=2; Parser::Lexer lexer( infilename, false, false, false, false, false, no_cplusplus); compunit: &Parser::CompilationUnit = Parser::GetCompilationUnit( lexer, true, false, false, false); std::ofstream outfile( outfilename.c_str()); if ( !outfile) throw std::runtime_error( "Couldn't open for writing"); OutStream2 out( outfile); out.have_seen_hierprof_function = immediate; outfile << "#line 1 \"" << infilename << "\"\n"; //outfile << "#include \"HierProf/HierProf.h\"\n"; //outfile << "#line 1 \"" << infilename << "\"\n"; Output2( compunit, out); else throw std::runtime_error( std::string("Unrecognised param `") + argv[arg] + "'"); return 0;; catch ( std::exception& e) std::cerr << e.what() << "\n"; return 1;