#include "externals.hh" #include "c-opast.hh" #include "c-ops.hh" #include "c-opcomp.hh" #include "c-opopt.hh" #include #include #include #include using namespace ebcl; using namespace opast; #define M_LOGSTR( S , L ) \ logger( [](){ return T_StringBuilder{ S }; } , L ) namespace { const struct option CmdLineOpts_[] = { { "log-level" , required_argument , 0 , 'L' } , { "source-path" , required_argument , 0 , 's' } , { "config" , required_argument , 0 , 'c' } , { 0 , 0 , 0 , 0 } }; /*============================================================================*/ void PrintStreamError( char const* const prefix , T_String const& name , X_StreamError const& error ) noexcept { T_StringBuilder sb; sb << prefix << " '" << name << "': " << error.what( ); if ( error.code( ) == E_StreamError::SYSTEM_ERROR ) { sb << " (error code " << error.systemError( ) << ")"; } sb << '\n' << '\0'; fprintf( stderr , "%s" , sb.data( ) ); } void WriteSRDError( T_StringBuilder& sb , T_SRDError const& error ) noexcept { switch ( error.type( ) ) { case E_SRDErrorType::ERROR: sb << "[ERROR"; break; case E_SRDErrorType::WARNING: sb << " [WARN"; break; case E_SRDErrorType::NOTE: sb << " [NOTE"; break; } sb << '(' << error.location( ) << ")] " << error.error( ) << '\n'; } void WriteSRDErrors( char const* const title , T_SRDErrors const& errors ) noexcept { T_StringBuilder sb; sb << "===== " << title << '\n'; const auto nErrors( errors.size( ) ); for ( auto i = 0u ; i < nErrors ; i ++ ) { WriteSRDError( sb , errors[ i ] ); } sb << '\0'; fprintf( stderr , "%s" , sb.data( ) ); } void WriteSRDErrors( char const* const title , T_Array< T_SRDError > const& errors ) noexcept { T_StringBuilder sb; sb << "===== " << title << '\n'; const auto nErrors( errors.size( ) ); for ( auto i = 0u ; i < nErrors ; i ++ ) { WriteSRDError( sb , errors[ i ] ); } sb << '\0'; fprintf( stderr , "%s" , sb.data( ) ); } T_String FilePath( T_String const& path , char const* const name ) noexcept { T_StringBuilder sb; if ( path ) { sb << path; if ( !path.endsWith( "/" ) ) { sb << '/'; } } sb << name; return T_String{ std::move( sb ) }; } /*============================================================================*/ } // namespace int main( int argc , char** argv ) { // Parse command line T_Optional< uint32_t > oLogLevel; T_String oSrcPath; T_String oBuildCfg; int c; while ( ( c = getopt_long( argc , argv , "L:s:c:" , CmdLineOpts_ , nullptr ) ) != -1 ) { switch ( c ) { case 'L': oLogLevel = uint32_t( atoi( optarg ) ); break; case 's': if ( oSrcPath ) { fprintf( stderr , "Duplicate source path\n" ); return EXIT_FAILURE; } oSrcPath = optarg; break; case 'c': if ( oSrcPath ) { fprintf( stderr , "Duplicate build configuration\n" ); return EXIT_FAILURE; } oBuildCfg = optarg; break; } } // Logger setup const uint32_t logLevel{ oLogLevel ? *oLogLevel : 0 }; const auto logger{ [=]( F_OPGenLog func , uint32_t level ) { if ( level > logLevel ) { return; } auto sb{ func( ) }; sb << '\0'; printf( "(%d) %s\n" , level , sb.data( ) ); } }; // Build configurations M_LOGSTR( "Loading build configurations" , 1 ); const T_String bcfgFile{ FilePath( oSrcPath , "build.srd" ) }; const T_BuildConfiguration cfg{ [&]() { try { T_BuildConfigurationLoader bcfgLoader; T_BuildConfigurations cfs{ bcfgLoader.load( bcfgFile ) }; if ( oBuildCfg && !cfs.contains( oBuildCfg ) ) { fprintf( stderr , "===== BUILD CONFIGURATIONS\n" ); fprintf( stderr , "Build configuration not found\n" ); exit( EXIT_FAILURE ); } if ( oBuildCfg ) { return *cfs.get( oBuildCfg ); } if ( cfs.size( ) ) { return cfs[ 0 ]; } return T_BuildConfiguration{ }; } catch ( X_StreamError const& e ) { fprintf( stderr , "===== BUILD CONFIGURATIONS\n" ); PrintStreamError( "Could not open" , bcfgFile , e ); exit( EXIT_FAILURE ); } catch ( X_SRDErrors const& e ) { WriteSRDErrors( "BUILD CONFIGURATIONS" , e.errors ); exit( EXIT_FAILURE ); } } () }; // Load curves M_LOGSTR( "Loading curves data" , 1 ); const T_String curvesFile{ FilePath( oSrcPath , "curves.srd" ) }; T_SyncCurvesIO::T_Data p; try { p = T_SyncCurvesIO{}.load( curvesFile ); } catch ( ebcl::X_StreamError const& e ) { fprintf( stderr , "===== CURVES DATA\n" ); PrintStreamError( "Could not open" , curvesFile , e ); exit( EXIT_FAILURE ); } catch ( ebcl::X_SRDErrors const& e ) { WriteSRDErrors( "CURVES DATA" , e.errors ); exit( EXIT_FAILURE ); } // Open and load script M_LOGSTR( "Loading script" , 1 ); const T_String inputName{ FilePath( oSrcPath , "demo.srd" ) }; T_SRDMemoryTarget srdOut; { T_File input( inputName , E_FileMode::READ_ONLY ); try { input.open( ); } catch ( X_StreamError const& e ) { PrintStreamError( "Could not open" , inputName , e ); return 1; } srdOut.clearComments( true ).clearFlushToken( true ); try { T_SRDTextReader srdReader{ srdOut }; T_FileInputStream fis{ input }; srdReader.read( inputName , fis ); } catch ( X_StreamError const& e ) { fprintf( stderr , "===== SCRIPT\n" ); PrintStreamError( "Could not open" , inputName , e ); exit( EXIT_FAILURE ); } catch ( X_SRDErrors const& e ) { WriteSRDErrors( "SCRIPT" , e.errors ); exit( EXIT_FAILURE ); } } // Parse script M_LOGSTR( "Parsing script" , 1 ); T_OpsParser parser; parser.setLogger( logger ); if ( !parser.parse( srdOut.list( ) ) ) { WriteSRDErrors( "SCRIPT" , parser.errors( ) ); exit( EXIT_FAILURE ); } auto parsed{ parser.result( ) }; // Optimize if ( cfg.optimize ) { M_LOGSTR( "Optimizing script tree" , 1 ); opopt::T_OptData od; od.logger = logger; if ( !cfg.resolutionChooser && cfg.cfFixedSize ) { od.fixedSize = cfg.resolutions[ 0 ]; // FIXME } if ( cfg.cfInputs ) { od.curves = &p.curves; } bool doneStuff; do { doneStuff = false; if ( cfg.constantFolding ) { while ( opopt::FoldConstants( *parsed , od ) ) { doneStuff = true; } } if ( cfg.deadCodeElimination ) { while ( opopt::RemoveDeadCode( *parsed , od ) ) { doneStuff = true; } } } while ( doneStuff ); } // Compile M_LOGSTR( "Compiling script" , 1 ); T_OpsCompiler compiler; compiler.setLogger( logger ); compiler.compile( *parsed ); return 0; }