Parser - Check local variable declarations

This commit is contained in:
Emmanuel BENOîT 2017-11-11 09:54:38 +01:00
parent e21e5cefb2
commit 36a3e5e26f
3 changed files with 109 additions and 20 deletions

View file

@ -315,6 +315,18 @@ A_FuncNode::A_FuncNode(
instructions_( *this ) 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 ===============================================================*/ /*= T_RootNode ===============================================================*/
@ -359,15 +371,28 @@ T_Optional< T_SRDLocation > T_FuncNode::addArgument(
assert( token.type( ) == E_SRDTokenType::WORD ); assert( token.type( ) == E_SRDTokenType::WORD );
assert( token.hasLocation( ) ); assert( token.hasLocation( ) );
const auto pnp( argNames_.indexOf( token.stringValue( ) ) ); const auto pnp( locals_.indexOf( token.stringValue( ) ) );
if ( pnp != -1 ) { if ( pnp != T_HashIndex::INVALID_INDEX ) {
return argLocations_[ pnp ]; return locals_[ pnp ].location;
} }
argNames_.add( token.stringValue( ) ); locals_.add( T_Local_{ token.stringValue( ) , token.location( ) , true } );
argLocations_.add( token.location( ) );
return {}; 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 ======================================================*/ /*= T_PipelineInstrNode ======================================================*/
@ -551,13 +576,14 @@ T_Optional< T_SRDLocation > T_SamplerInstrNode::setLOD(
/*= T_LocalsInstrNode ===========================================================*/ /*= T_LocalsInstrNode ===========================================================*/
bool T_LocalsInstrNode::addVariable( T_Optional< T_SRDLocation > T_LocalsInstrNode::addVariable(
T_SRDToken const& token ) noexcept T_SRDToken const& token ) noexcept
{ {
if ( vars_.contains( token.stringValue( ) ) ) { const auto pnp( vars_.indexOf( token.stringValue( ) ) );
return false; if ( pnp != -1 ) {
return varLocs_[ pnp ];
} }
vars_.add( token.stringValue( ) ); vars_.add( token.stringValue( ) );
varLocs_.add( token.location( ) ); varLocs_.add( token.location( ) );
return true; return {};
} }

View file

@ -198,6 +198,27 @@ class A_FuncNode : public A_Node
T_String name_; T_String name_;
T_InstrListNode instructions_; 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: protected:
// For init or frame entry points. // For init or frame entry points.
// isInit = true => init entry point // isInit = true => init entry point
@ -217,6 +238,10 @@ class A_FuncNode : public A_Node
{ return instructions_; } { return instructions_; }
T_InstrListNode const& instructions( ) const noexcept T_InstrListNode const& instructions( ) const noexcept
{ return instructions_; } { return instructions_; }
T_Optional< T_SRDLocation > addLocalVariable(
T_String const& name ,
T_SRDLocation const& location ) noexcept;
}; };
using P_InstrListNode = T_OwnPtr< T_InstrListNode >; using P_InstrListNode = T_OwnPtr< T_InstrListNode >;
@ -293,10 +318,6 @@ class T_SpecialFuncNode : public A_FuncNode
// Normal functions // Normal functions
class T_FuncNode : public A_FuncNode class T_FuncNode : public A_FuncNode
{ {
private:
T_AutoArray< T_String , 8 > argNames_;
T_AutoArray< T_SRDLocation , 8 > argLocations_;
public: public:
T_FuncNode( T_String const& name , T_FuncNode( T_String const& name ,
T_RootNode& parent ) noexcept T_RootNode& parent ) noexcept
@ -308,8 +329,7 @@ class T_FuncNode : public A_FuncNode
T_Optional< T_SRDLocation > addArgument( T_Optional< T_SRDLocation > addArgument(
T_SRDToken const& token ) noexcept; T_SRDToken const& token ) noexcept;
uint32_t arguments( ) const noexcept uint32_t arguments( ) const noexcept;
{ return argNames_.size( ); }
}; };
@ -407,7 +427,8 @@ class T_LocalsInstrNode : public A_InstructionNode
: A_InstructionNode( OP_LOCALS , parent ) : 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 uint32_t variables( ) const noexcept
{ return vars_.size( ); } { return vars_.size( ); }

View file

@ -171,6 +171,7 @@ struct T_ParserImpl_
bool checkCalls( ) noexcept; bool checkCalls( ) noexcept;
bool checkInstructionRestrictions( ) noexcept; bool checkInstructionRestrictions( ) noexcept;
bool collectGlobalTypes( ) noexcept; bool collectGlobalTypes( ) noexcept;
bool checkLocalVariables( ) noexcept;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
@ -282,7 +283,8 @@ void T_ParserImpl_::main(
&& checkRequiredBlocks( input ) && checkRequiredBlocks( input )
&& checkCalls( ) && checkCalls( )
&& checkInstructionRestrictions( ) && checkInstructionRestrictions( )
&& collectGlobalTypes( ); && collectGlobalTypes( )
&& checkLocalVariables( );
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
@ -458,6 +460,39 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
return errors.empty( ); 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( bool T_ParserImpl_::parseTopLevel(
@ -830,15 +865,22 @@ M_INSTR_( Local )
auto& instr{ instructions.add< T_LocalsInstrNode >( ) }; auto& instr{ instructions.add< T_LocalsInstrNode >( ) };
instr.location( ) = input[ 0 ].location( ); instr.location( ) = input[ 0 ].location( );
T_StringBuilder sb;
for ( auto i = 1u ; i < ni ; i ++ ) { for ( auto i = 1u ; i < ni ; i ++ ) {
auto const& token( input[ i ] ); auto const& token( input[ i ] );
if ( token.type( ) != E_SRDTokenType::WORD ) { if ( token.type( ) != E_SRDTokenType::WORD ) {
errors.addNew( "variable identifier expected" , errors.addNew( "variable identifier expected" ,
token.location( ) ); token.location( ) );
} else if ( !instr.addVariable( token ) ) { continue;
errors.addNew( "duplicate variable identifier" ,
token.location( ) );
} }
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( ) );
} }
} }