From 36a3e5e26fe754388a45b6844b370906f41e3fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 11 Nov 2017 09:54:38 +0100 Subject: [PATCH] Parser - Check local variable declarations --- opast.cc | 44 +++++++++++++++++++++++++++++++++++--------- opast.hh | 35 ++++++++++++++++++++++++++++------- opparser.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 109 insertions(+), 20 deletions(-) diff --git a/opast.cc b/opast.cc index fdf0b3d..949f1af 100644 --- a/opast.cc +++ b/opast.cc @@ -315,6 +315,18 @@ A_FuncNode::A_FuncNode( instructions_( *this ) { } +T_Optional< T_SRDLocation > A_FuncNode::addLocalVariable( + T_String const& name , + T_SRDLocation const& location ) noexcept +{ + auto const* const pnp( locals_.get( name ) ); + if ( pnp ) { + return pnp->location; + } + locals_.add( T_Local_{ name , location , false } ); + return {}; +} + /*= T_RootNode ===============================================================*/ @@ -359,15 +371,28 @@ T_Optional< T_SRDLocation > T_FuncNode::addArgument( assert( token.type( ) == E_SRDTokenType::WORD ); assert( token.hasLocation( ) ); - const auto pnp( argNames_.indexOf( token.stringValue( ) ) ); - if ( pnp != -1 ) { - return argLocations_[ pnp ]; + const auto pnp( locals_.indexOf( token.stringValue( ) ) ); + if ( pnp != T_HashIndex::INVALID_INDEX ) { + return locals_[ pnp ].location; } - argNames_.add( token.stringValue( ) ); - argLocations_.add( token.location( ) ); + locals_.add( T_Local_{ token.stringValue( ) , token.location( ) , true } ); return {}; } +uint32_t T_FuncNode::arguments( ) const noexcept +{ + const auto n( locals_.size( ) ); + uint32_t na{ 0u }; + + for ( auto i = 0u ; i < n ; i ++ ) { + if ( locals_[ i ].argument ) { + na ++; + } + } + + return na; +} + /*= T_PipelineInstrNode ======================================================*/ @@ -551,13 +576,14 @@ T_Optional< T_SRDLocation > T_SamplerInstrNode::setLOD( /*= T_LocalsInstrNode ===========================================================*/ -bool T_LocalsInstrNode::addVariable( +T_Optional< T_SRDLocation > T_LocalsInstrNode::addVariable( T_SRDToken const& token ) noexcept { - if ( vars_.contains( token.stringValue( ) ) ) { - return false; + const auto pnp( vars_.indexOf( token.stringValue( ) ) ); + if ( pnp != -1 ) { + return varLocs_[ pnp ]; } vars_.add( token.stringValue( ) ); varLocs_.add( token.location( ) ); - return true; + return {}; } diff --git a/opast.hh b/opast.hh index 9cd069c..e21021e 100644 --- a/opast.hh +++ b/opast.hh @@ -198,6 +198,27 @@ class A_FuncNode : public A_Node T_String name_; T_InstrListNode instructions_; + protected: + struct T_Local_ + { + T_String name; + T_SRDLocation location; + bool argument; + E_DataType type{ E_DataType::UNKNOWN }; + + T_Local_( T_String const& name , + T_SRDLocation const& location , + const bool argument ) noexcept + : name{ name } , location{ location } , + argument{ argument } + { } + }; + T_ObjectTable< T_String , T_Local_ > locals_{ + []( T_Local_ const& l ) -> T_String { + return l.name; + } + }; + protected: // For init or frame entry points. // isInit = true => init entry point @@ -217,6 +238,10 @@ class A_FuncNode : public A_Node { return instructions_; } T_InstrListNode const& instructions( ) const noexcept { return instructions_; } + + T_Optional< T_SRDLocation > addLocalVariable( + T_String const& name , + T_SRDLocation const& location ) noexcept; }; using P_InstrListNode = T_OwnPtr< T_InstrListNode >; @@ -293,10 +318,6 @@ class T_SpecialFuncNode : public A_FuncNode // Normal functions class T_FuncNode : public A_FuncNode { - private: - T_AutoArray< T_String , 8 > argNames_; - T_AutoArray< T_SRDLocation , 8 > argLocations_; - public: T_FuncNode( T_String const& name , T_RootNode& parent ) noexcept @@ -308,8 +329,7 @@ class T_FuncNode : public A_FuncNode T_Optional< T_SRDLocation > addArgument( T_SRDToken const& token ) noexcept; - uint32_t arguments( ) const noexcept - { return argNames_.size( ); } + uint32_t arguments( ) const noexcept; }; @@ -407,7 +427,8 @@ class T_LocalsInstrNode : public A_InstructionNode : A_InstructionNode( OP_LOCALS , parent ) { } - bool addVariable( T_SRDToken const& token ) noexcept; + T_Optional< T_SRDLocation > addVariable( + T_SRDToken const& token ) noexcept; uint32_t variables( ) const noexcept { return vars_.size( ); } diff --git a/opparser.cc b/opparser.cc index 5df82ff..ca7339a 100644 --- a/opparser.cc +++ b/opparser.cc @@ -171,6 +171,7 @@ struct T_ParserImpl_ bool checkCalls( ) noexcept; bool checkInstructionRestrictions( ) noexcept; bool collectGlobalTypes( ) noexcept; + bool checkLocalVariables( ) noexcept; // --------------------------------------------------------------------- @@ -282,7 +283,8 @@ void T_ParserImpl_::main( && checkRequiredBlocks( input ) && checkCalls( ) && checkInstructionRestrictions( ) - && collectGlobalTypes( ); + && collectGlobalTypes( ) + && checkLocalVariables( ); } /*----------------------------------------------------------------------------*/ @@ -458,6 +460,39 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept return errors.empty( ); } +bool T_ParserImpl_::checkLocalVariables( ) noexcept +{ + uint32_t cfi; + for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) { + auto& function( output->root.function( cfi ) ); + T_StringBuilder esb; + visitor.visit( function , + [&]( A_Node& n , const bool exit ) -> bool { + if ( exit || n.type( ) != A_Node::OP_LOCALS ) { + return true; + } + + auto& locals( dynamic_cast< T_LocalsInstrNode& >( n ) ); + for ( auto i = 0u ; i < locals.variables( ) ; i ++ ) { + auto prev{ function.addLocalVariable( + locals.varName( i ) , + locals.varLocation( i ) ) }; + if ( !prev ) { + continue; + } + + esb << "duplicate local '" << locals.varName( i ) + << "'; previous declaration at " + << *prev; + errors.addNew( std::move( esb ) , locals.varLocation( i ) ); + } + + return false; + } ); + } + return errors.empty( ); +} + /*------------------------------------------------------------------------------*/ bool T_ParserImpl_::parseTopLevel( @@ -830,15 +865,22 @@ M_INSTR_( Local ) auto& instr{ instructions.add< T_LocalsInstrNode >( ) }; instr.location( ) = input[ 0 ].location( ); + T_StringBuilder sb; for ( auto i = 1u ; i < ni ; i ++ ) { auto const& token( input[ i ] ); if ( token.type( ) != E_SRDTokenType::WORD ) { errors.addNew( "variable identifier expected" , token.location( ) ); - } else if ( !instr.addVariable( token ) ) { - errors.addNew( "duplicate variable identifier" , - token.location( ) ); + continue; } + const auto prev{ instr.addVariable( token ) }; + if ( !prev ) { + continue; + } + sb << "duplicate local '" << token.stringValue( ) + << "'; previous declaration at " + << *prev; + errors.addNew( std::move( sb ) , token.location( ) ); } }