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_InstrListNode& parent ,
T_SRDToken const& idToken ) noexcept
: A_InstructionNode( OP_PIPELINE , parent ) ,
: A_InstructionNode( OP_PIPELINE , parent , E_InstrRestriction::FRAME ) ,
id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) )
{ }
T_PipelineInstrNode::T_PipelineInstrNode(
T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_PIPELINE , parent ) ,
: A_InstructionNode( OP_PIPELINE , parent , E_InstrRestriction::FRAME ) ,
id_( "*invalid*" ) ,
idLocation_{ }
{ }
@ -160,7 +160,7 @@ T_Optional< T_SRDLocation > T_PipelineInstrNode::addProgram(
T_ProfileInstrNode::T_ProfileInstrNode(
T_InstrListNode& parent ,
T_String const& text ) noexcept
: A_InstructionNode( OP_PROFILE , parent ) ,
: A_InstructionNode( OP_PROFILE , parent , E_InstrRestriction::INIT ) ,
text_( text ) ,
instructions_( *this )
{ }
@ -172,7 +172,7 @@ T_ProgramInstrNode::T_ProgramInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& idToken ,
T_SRDToken const& pathToken ) noexcept
: A_InstructionNode( OP_PROGRAM , parent ) ,
: A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) ,
id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) ) ,
path_( pathToken.stringValue( ) ) ,
@ -197,7 +197,7 @@ T_TextureInstrNode::T_TextureInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& idToken ,
const E_TexType type ) noexcept
: A_InstructionNode( OP_PROGRAM , parent ) ,
: A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) ,
id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) ) ,
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
class A_InstructionNode : public A_Node
{
private:
const T_InstrRestriction restriction_;
protected:
A_InstructionNode( E_Type type ,
A_Node& parent ) noexcept
: A_Node( type , &parent )
{}
A_InstructionNode( const E_Type type ,
A_Node& 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
class T_InstrListNode : public A_Node
{
@ -341,14 +363,14 @@ class T_InputInstrNode : public A_InstructionNode
public:
T_InputInstrNode( T_InstrListNode& parent ,
T_SRDToken const& tName ) noexcept
: A_InstructionNode( OP_INPUT , parent ) ,
: A_InstructionNode( OP_INPUT , parent , E_InstrRestriction::FRAME ) ,
name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) )
{}
T_InputInstrNode( T_InstrListNode& parent ,
T_SRDToken const& tName ,
T_SRDToken const& tDefault ) noexcept
: A_InstructionNode( OP_INPUT , parent ) ,
: A_InstructionNode( OP_INPUT , parent , E_InstrRestriction::FRAME ) ,
name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) ) ,
defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) )
{}

View file

@ -239,30 +239,54 @@ bool checkCalls( T_RootNode& root )
}
return {};
} );
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( ) ];
T_InstrRestriction callInfo[ calls.size( ) ];
callGraphVisitor.visit( root.functionIndex( "*init*" ) ,
[&]( uint32_t id , const bool exit ) -> bool {
if ( exit || callInfo[ id ] & E_CallInfo_::INIT_CALLED ) {
if ( exit || callInfo[ id ] & E_InstrRestriction::INIT ) {
return false;
}
callInfo[ id ] |= E_CallInfo_::INIT_CALLED;
callInfo[ id ] |= E_InstrRestriction::INIT;
return true;
} );
callGraphVisitor.visit( root.functionIndex( "*frame*" ) ,
[&]( uint32_t id , const bool exit ) -> bool {
if ( exit || callInfo[ id ] & E_CallInfo_::FRAME_CALLED ) {
if ( exit || callInfo[ id ] & E_InstrRestriction::FRAME ) {
return false;
}
callInfo[ id ] |= E_CallInfo_::FRAME_CALLED;
callInfo[ id ] |= E_InstrRestriction::FRAME;
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;
for ( auto callerId = 0u ; callerId < calls.size( ) ; callerId ++ ) {
const auto nCallees( calls.sizeOf( callerId ) );