Parser - prototype - restrictions on instruction use

This commit is contained in:
Emmanuel BENOîT 2017-11-08 11:48:24 +01:00
parent c093ba2213
commit 397f1c5c75
3 changed files with 67 additions and 21 deletions

View file

@ -129,14 +129,14 @@ T_Optional< T_SRDLocation > T_FuncNode::addArgument(
T_PipelineInstrNode::T_PipelineInstrNode( T_PipelineInstrNode::T_PipelineInstrNode(
T_InstrListNode& parent , T_InstrListNode& parent ,
T_SRDToken const& idToken ) noexcept T_SRDToken const& idToken ) noexcept
: A_InstructionNode( OP_PIPELINE , parent ) , : A_InstructionNode( OP_PIPELINE , parent , E_InstrRestriction::FRAME ) ,
id_( idToken.stringValue( ) ) , id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) ) idLocation_( idToken.location( ) )
{ } { }
T_PipelineInstrNode::T_PipelineInstrNode( T_PipelineInstrNode::T_PipelineInstrNode(
T_InstrListNode& parent ) noexcept T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_PIPELINE , parent ) , : A_InstructionNode( OP_PIPELINE , parent , E_InstrRestriction::FRAME ) ,
id_( "*invalid*" ) , id_( "*invalid*" ) ,
idLocation_{ } idLocation_{ }
{ } { }
@ -160,7 +160,7 @@ T_Optional< T_SRDLocation > T_PipelineInstrNode::addProgram(
T_ProfileInstrNode::T_ProfileInstrNode( T_ProfileInstrNode::T_ProfileInstrNode(
T_InstrListNode& parent , T_InstrListNode& parent ,
T_String const& text ) noexcept T_String const& text ) noexcept
: A_InstructionNode( OP_PROFILE , parent ) , : A_InstructionNode( OP_PROFILE , parent , E_InstrRestriction::INIT ) ,
text_( text ) , text_( text ) ,
instructions_( *this ) instructions_( *this )
{ } { }
@ -172,7 +172,7 @@ T_ProgramInstrNode::T_ProgramInstrNode(
T_InstrListNode& parent , T_InstrListNode& parent ,
T_SRDToken const& idToken , T_SRDToken const& idToken ,
T_SRDToken const& pathToken ) noexcept T_SRDToken const& pathToken ) noexcept
: A_InstructionNode( OP_PROGRAM , parent ) , : A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) ,
id_( idToken.stringValue( ) ) , id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) ) , idLocation_( idToken.location( ) ) ,
path_( pathToken.stringValue( ) ) , path_( pathToken.stringValue( ) ) ,
@ -197,7 +197,7 @@ T_TextureInstrNode::T_TextureInstrNode(
T_InstrListNode& parent , T_InstrListNode& parent ,
T_SRDToken const& idToken , T_SRDToken const& idToken ,
const E_TexType type ) noexcept const E_TexType type ) noexcept
: A_InstructionNode( OP_PROGRAM , parent ) , : A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) ,
id_( idToken.stringValue( ) ) , id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) ) , idLocation_( idToken.location( ) ) ,
type_( type ) type_( type )

View file

@ -76,16 +76,38 @@ class A_Node
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
// Some instructions are restricted to either the initialisation code or the
// frame code.
enum class E_InstrRestriction
{
INIT , FRAME
};
using T_InstrRestriction = T_Flags< E_InstrRestriction >;
// Base class for instruction nodes // Base class for instruction nodes
class A_InstructionNode : public A_Node class A_InstructionNode : public A_Node
{ {
private:
const T_InstrRestriction restriction_;
protected: protected:
A_InstructionNode( E_Type type , A_InstructionNode( const E_Type type ,
A_Node& parent ) noexcept A_Node& parent ,
: A_Node( type , &parent ) T_InstrRestriction restriction = {} ) noexcept
{} : A_Node( type , &parent ) ,
restriction_( restriction )
{
assert( !restriction_.isSet({
E_InstrRestriction::INIT ,
E_InstrRestriction::FRAME }) );
}
public:
T_InstrRestriction restriction( ) const noexcept
{ return restriction_; }
}; };
// Nodes that store lists of instructions // Nodes that store lists of instructions
class T_InstrListNode : public A_Node class T_InstrListNode : public A_Node
{ {
@ -341,14 +363,14 @@ class T_InputInstrNode : public A_InstructionNode
public: public:
T_InputInstrNode( T_InstrListNode& parent , T_InputInstrNode( T_InstrListNode& parent ,
T_SRDToken const& tName ) noexcept T_SRDToken const& tName ) noexcept
: A_InstructionNode( OP_INPUT , parent ) , : A_InstructionNode( OP_INPUT , parent , E_InstrRestriction::FRAME ) ,
name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) ) name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) )
{} {}
T_InputInstrNode( T_InstrListNode& parent , T_InputInstrNode( T_InstrListNode& parent ,
T_SRDToken const& tName , T_SRDToken const& tName ,
T_SRDToken const& tDefault ) noexcept T_SRDToken const& tDefault ) noexcept
: A_InstructionNode( OP_INPUT , parent ) , : A_InstructionNode( OP_INPUT , parent , E_InstrRestriction::FRAME ) ,
name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) ) , name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) ) ,
defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) ) defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) )
{} {}

View file

@ -239,30 +239,54 @@ bool checkCalls( T_RootNode& root )
} }
return {}; return {};
} ); } );
enum class E_CallInfo_ { T_InstrRestriction callInfo[ calls.size( ) ];
INIT_CHECKED , FRAME_CHECKED ,
INIT_CALLED , FRAME_CALLED
};
using T_CallInfo_ = T_Flags< E_CallInfo_ , uint8_t >;
T_CallInfo_ callInfo[ calls.size( ) ];
callGraphVisitor.visit( root.functionIndex( "*init*" ) , callGraphVisitor.visit( root.functionIndex( "*init*" ) ,
[&]( uint32_t id , const bool exit ) -> bool { [&]( uint32_t id , const bool exit ) -> bool {
if ( exit || callInfo[ id ] & E_CallInfo_::INIT_CALLED ) { if ( exit || callInfo[ id ] & E_InstrRestriction::INIT ) {
return false; return false;
} }
callInfo[ id ] |= E_CallInfo_::INIT_CALLED; callInfo[ id ] |= E_InstrRestriction::INIT;
return true; return true;
} ); } );
callGraphVisitor.visit( root.functionIndex( "*frame*" ) , callGraphVisitor.visit( root.functionIndex( "*frame*" ) ,
[&]( uint32_t id , const bool exit ) -> bool { [&]( uint32_t id , const bool exit ) -> bool {
if ( exit || callInfo[ id ] & E_CallInfo_::FRAME_CALLED ) { if ( exit || callInfo[ id ] & E_InstrRestriction::FRAME ) {
return false; return false;
} }
callInfo[ id ] |= E_CallInfo_::FRAME_CALLED; callInfo[ id ] |= E_InstrRestriction::FRAME;
return true; return true;
} ); } );
for ( auto i = 0u ; i < root.nFunctions( ) ; i ++ ) {
visitor.visit( root.function( i ) ,
[&]( A_Node& node , bool exit ) {
if ( exit ) {
return false;
}
auto const* instr( dynamic_cast< A_InstructionNode const* >( &node ) );
if ( instr && ( instr->restriction( ) & callInfo[ i ] ) ) {
T_StringBuilder sb;
sb << "instruction not allowed in "
<< ( ( instr->restriction( ) & E_InstrRestriction::INIT )
? "initialisation" : "frame function" );
errors.addNew( std::move( sb ) , instr->location( ) );
}
return true;
} );
}
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_StringBuilder sb; T_StringBuilder sb;
for ( auto callerId = 0u ; callerId < calls.size( ) ; callerId ++ ) { for ( auto callerId = 0u ; callerId < calls.size( ) ; callerId ++ ) {
const auto nCallees( calls.sizeOf( callerId ) ); const auto nCallees( calls.sizeOf( callerId ) );