From 14288e3c87bdb6936947ed11f05bf446830c58f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Tue, 7 Nov 2017 13:24:01 +0100 Subject: [PATCH] Parser - Prototyping call checks --- opast.cc | 1 + opast.hh | 5 ++ parsercheck.cc | 220 ++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 198 insertions(+), 28 deletions(-) diff --git a/opast.cc b/opast.cc index da080db..1f65085 100644 --- a/opast.cc +++ b/opast.cc @@ -614,6 +614,7 @@ M_INSTR_( Call ) } auto& instr{ instructions.add< T_CallInstrNode >( input[ 1 ] ) }; + instr.location( ) = input[ 0 ].location( ); for ( auto it = input.begin( ) + 2 ; it.valid( ) ; ++it ) { instr.addArgument( parseExpression( instr , *it ) ); } diff --git a/opast.hh b/opast.hh index 4844cc3..a5171e5 100644 --- a/opast.hh +++ b/opast.hh @@ -197,6 +197,8 @@ class T_RootNode : public A_Node uint32_t nFunctions( ) const noexcept { return functions_.size( ); } + int32_t functionIndex( T_String const& name ) const noexcept + { return functions_.indexOf( name ); } A_FuncNode& function( const uint32_t index ) const noexcept { return *functions_.values( )[ index ]; } }; @@ -227,6 +229,9 @@ class T_FuncNode : public A_FuncNode // of the initial argument. T_Optional< T_SRDLocation > addArgument( T_SRDToken const& token ) noexcept; + + uint32_t arguments( ) const noexcept + { return argNames_.size( ); } }; /*----------------------------------------------------------------------------*/ diff --git a/parsercheck.cc b/parsercheck.cc index d085b16..6c5a429 100644 --- a/parsercheck.cc +++ b/parsercheck.cc @@ -8,9 +8,98 @@ using namespace opast; namespace { +/*============================================================================*/ + + +void PrintStreamError( + char const* const prefix , + T_String const& name , + X_StreamError const& error ) +{ + 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 ) +{ + sb << error.location( ) << " - " << error.error( ) << "\n"; +} + + /*============================================================================*/ // FIXME TESTING, MOVE THIS LATER +template< + typename Enum , + typename Storage = uint32_t +> class T_Flags +{ + private: + Storage flags_; + + public: + constexpr T_Flags( ) noexcept + : flags_( 0 ) {} + + constexpr T_Flags( T_Flags const& other ) noexcept + : flags_( other.flags_ ) { } + + constexpr T_Flags( const Enum flag ) noexcept + : flags_( 1 << int( flag ) ) {} + + constexpr T_Flags( std::initializer_list< Enum > flags ) noexcept + : flags_( 0 ) + { + for ( auto f : flags ) { + flags_ |= ( 1 << int( f ) ); + } + } + + explicit constexpr T_Flags( const Storage flags ) noexcept + : flags_( flags ) { } + + constexpr T_Flags operator |=( T_Flags other ) noexcept + { flags_ |= other.flags_; return *this; } + constexpr T_Flags operator &=( T_Flags other ) noexcept + { flags_ &= other.flags_; return *this; } + constexpr T_Flags operator ^=( T_Flags other ) noexcept + { flags_ ^= other.flags_; return *this; } + + constexpr T_Flags operator ~( ) const noexcept + { return T_Flags( ~flags_ ); } + constexpr T_Flags operator &( T_Flags other ) const noexcept + { return T_Flags( flags_ & other.flags_ ); } + constexpr T_Flags operator |( T_Flags other ) const noexcept + { return T_Flags( flags_ & other.flags_ ); } + constexpr T_Flags operator ^( T_Flags other ) const noexcept + { return T_Flags( flags_ ^ other.flags_ ); } + + constexpr operator bool( ) const noexcept + { return flags_ != 0; } + constexpr bool operator!( ) const noexcept + { return flags_ == 0; } + explicit constexpr operator Storage( ) const noexcept + { return flags_; } + + constexpr bool operator ==( const T_Flags other ) const noexcept + { return flags_ == other.flags_; } + constexpr bool operator !=( const T_Flags other ) const noexcept + { return flags_ != other.flags_; } + + constexpr bool isSet( const T_Flags value ) const noexcept + { return ( *this & value ) == value; } + constexpr bool isClear( const T_Flags value ) const noexcept + { return !( *this & value ); } +}; + + template< typename NodeType > class T_Visitor { @@ -45,7 +134,7 @@ class T_Visitor public: T_Visitor( ) = delete; - T_Visitor( T_Visitor const& ) noexcept = default; + T_Visitor( T_Visitor const& ) = default; T_Visitor( T_Visitor&& ) noexcept = default; explicit T_Visitor( F_NodeBrowser browser ) noexcept; @@ -231,30 +320,111 @@ A_Node* OpASTBrowser( } -/*============================================================================*/ - - -void PrintStreamError( - char const* const prefix , - T_String const& name , - X_StreamError const& error ) +bool checkCalls( T_RootNode& root ) { - T_StringBuilder sb; - sb << prefix << " '" << name << "': " << error.what( ); - if ( error.code( ) == E_StreamError::SYSTEM_ERROR ) { - sb << " (error code " << error.systemError( ) << ")"; + T_Visitor< A_Node > visitor( OpASTBrowser ); + T_Array< T_SRDError > errors; + + T_MultiArray< uint32_t > calls; + uint32_t cfi; + for ( cfi = 0 ; cfi < root.nFunctions( ) ; cfi ++ ) { + calls.next( ); + visitor.visit( root.function( cfi ) , [&]( A_Node& node , bool exit ) -> bool { + if ( exit || dynamic_cast< A_ExpressionNode* >( &node ) ) { + return false; + } + if ( node.type( ) != A_Node::OP_CALL ) { + return true; + } + + auto& call( (T_CallInstrNode&) node ); + const auto callee( root.functionIndex( call.id( ) ) ); + if ( callee >= 0 ) { + if ( !calls.contains( cfi , callee ) ) { + calls.add( (uint32_t) callee ); + } + + // Check argument count while we're at it + auto& fn( (T_FuncNode&) root.function( callee ) ); + if ( fn.arguments( ) != call.arguments( ) ) { + T_StringBuilder sb; + sb << "function expects " << fn.arguments( ) + << " argument" << ( fn.arguments( ) == 1 ? "" : "s" ) + << ", " << call.arguments( ) + << " argument" << ( call.arguments( ) == 1 ? "" : "s" ) + << " provided"; + errors.addNew( std::move( sb ) , call.location( ) ); + } + } else { + errors.addNew( "unknown function" , call.idLocation( ) ); + } + return false; + } ); } - sb << '\n' << '\0'; - fprintf( stderr , "%s" , sb.data( ) ); -} - -void WriteSRDError( - T_StringBuilder& sb , - T_SRDError const& error ) -{ - sb << error.location( ) << " - " << error.error( ) << "\n"; + + if ( !errors.empty( ) ) { + T_StringBuilder sb; + for ( auto const& err : errors ) { + WriteSRDError( sb , err ); + } + sb << "Parser failed\n" << '\0'; + fprintf( stderr , "%s" , sb.data( ) ); + return false; + } + + T_Visitor< uint32_t > callGraphVisitor( + [&]( uint32_t& v , uint32_t child ) -> uint32_t* { + const uint32_t nc( calls.sizeOf( v ) ); + if ( child < nc ) { + return &calls.get( v , child ); + } + return nullptr; + } ); + enum class E_CallInfo_ { + INIT_CHECKED , FRAME_CHECKED , + INIT_CALLED , FRAME_CALLED + }; + using T_CallInfo_ = T_Flags< E_CallInfo_ , uint8_t >; + T_CallInfo_ callInfo[ calls.size( ) ]; + + uint32_t initId( root.functionIndex( "*init*" ) ); + callGraphVisitor.visit( initId , [&]( uint32_t& id , const bool exit ) -> bool { + if ( exit || callInfo[ id ] & E_CallInfo_::INIT_CALLED ) { + return false; + } + callInfo[ id ] |= E_CallInfo_::INIT_CALLED; + return true; + } ); + uint32_t frameId( root.functionIndex( "*frame*" ) ); + callGraphVisitor.visit( frameId , [&]( uint32_t& id , const bool exit ) -> bool { + if ( exit || callInfo[ id ] & E_CallInfo_::FRAME_CALLED ) { + return false; + } + callInfo[ id ] |= E_CallInfo_::FRAME_CALLED; + return true; + } ); + + T_StringBuilder sb; + for ( auto callerId = 0u ; callerId < calls.size( ) ; callerId ++ ) { + const auto nCallees( calls.sizeOf( callerId ) ); + if ( !nCallees ) { + continue; + } + sb << root.function( callerId ).name( ) << " calls"; + for ( auto i = 0u ; i < nCallees ; i ++ ) { + auto const& callee( root.function( calls.get( callerId , i ) ) ); + sb << ' ' << callee.name( ); + + } + sb << '\n'; + } + sb << '\0'; + printf( "%s" , sb.data( ) ); + + return true; } +/*============================================================================*/ } // namespace @@ -297,13 +467,7 @@ int main( int argc , char** argv ) printf( "Success!\n" ); auto result( parser.result( ) ); - T_Visitor< A_Node > visitor( OpASTBrowser ); - visitor.visit( *result , []( A_Node& node , bool enter ) { - if ( enter ) { - printf( "Enter node %p\n" , &node ); - } - return true; - } ); + checkCalls( *result ); return 0; } else { T_StringBuilder sb;