#include "externals.hh" #include "common.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_FSPath const& name , X_StreamError const& error ) noexcept { const T_FSPath rp{ ([&]() { if ( error.path( ) ) { return *( error.path( ) ); } return name; }()).makeRelative( Filesystem::Cwd( ) ) }; T_StringBuilder sb; sb << prefix << " '" << rp << "': " << 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_FSPath FilePath( T_FSPath const& path , char const* const name ) noexcept { const T_FSPath fp{ name }; if ( fp.isAbsolute( ) ) { return fp.canonical( ); } return ( path + fp ).canonical( ); } /*============================================================================*/ } // 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 ( oBuildCfg ) { fprintf( stderr , "Duplicate build configuration\n" ); return EXIT_FAILURE; } oBuildCfg = optarg; break; } } // Initialise common layer const T_FSPath srcPath{ ([&](){ const T_FSPath raw{ oSrcPath }; if ( !raw.isAbsolute( ) ) { return ( Filesystem::Cwd( ) + raw ).canonical( ); } return raw.canonical( ); })() }; if ( !srcPath.isValid( ) ) { fprintf( stderr , "Invalid source path\n" ); return EXIT_FAILURE; } Common common{ srcPath }; // 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_BuildConfiguration cfg{ [&]() { try { T_BuildConfigurations cfs{ T_BuildConfigurationLoader{ }.load( ) }; 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" , Common::Project( ).pathOf( "build.srd" ) , 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 auto curvesFile{ FilePath( srcPath , "curves.srd" ) }; T_SyncCurvesIO::T_Data p; try { p = T_SyncCurvesIO{}.load( curvesFile.toString( ) ); } 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 ); char const* const scriptName{ "demo.srd" }; const auto scriptPath{ Common::Project( ).pathOf( scriptName ) }; T_SRDMemoryTarget srdOut; { T_File input( scriptPath , E_FileMode::READ_ONLY ); try { input.open( ); } catch ( X_StreamError const& e ) { PrintStreamError( "Could not open" , scriptPath , e ); return 1; } srdOut.clearComments( true ).clearFlushToken( true ); try { T_SRDTextReader srdReader{ srdOut }; T_FileInputStream fis{ input }; srdReader.read( scriptName , fis ); } catch ( X_StreamError const& e ) { fprintf( stderr , "===== SCRIPT\n" ); PrintStreamError( "Could not open" , scriptPath , 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( scriptPath , 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 didStuff; do { didStuff = false; if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) { didStuff = true; } if ( cfg.constantPropagation && opopt::PropagateConstants( *parsed , od ) ) { didStuff = true; } if ( cfg.deadCodeElimination && opopt::RemoveDeadCode( *parsed , od ) ) { didStuff = true; } if ( cfg.inlineFunctions && opopt::InlineFunctions( *parsed , od ) ) { didStuff = true; } } while ( didStuff ); } // Compile M_LOGSTR( "Compiling script" , 1 ); T_OpsCompiler compiler( true ); compiler.setLogger( logger ); compiler.compile( *parsed ); return 0; }