Parser - Moved prototypes
Prototypes for -> call graph generation, argument count check -> enforcement of instruction restrictions moved to main parser code
This commit is contained in:
parent
b0401c5134
commit
d83743d072
3 changed files with 274 additions and 301 deletions
294
opast.cc
294
opast.cc
|
@ -1,5 +1,6 @@
|
||||||
#include "externals.hh"
|
#include "externals.hh"
|
||||||
#include "opast.hh"
|
#include "opast.hh"
|
||||||
|
#include <ebcl/Algorithms.hh>
|
||||||
|
|
||||||
using namespace ebcl;
|
using namespace ebcl;
|
||||||
using namespace opast;
|
using namespace opast;
|
||||||
|
@ -28,6 +29,149 @@ T_RootNode& A_Node::root( ) const noexcept
|
||||||
const_cast< A_Node* >( node ) );
|
const_cast< A_Node* >( node ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
A_Node* opast::ASTVisitorBrowser(
|
||||||
|
A_Node& node ,
|
||||||
|
const uint32_t child ) noexcept
|
||||||
|
{
|
||||||
|
switch ( node.type( ) ) {
|
||||||
|
|
||||||
|
// Root node
|
||||||
|
case A_Node::ROOT: {
|
||||||
|
auto& n( (T_RootNode&) node );
|
||||||
|
if ( child < n.nFunctions( ) ) {
|
||||||
|
return &n.function( child );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions / special blocks
|
||||||
|
case A_Node::DECL_FN: case A_Node::DECL_INIT: case A_Node::DECL_FRAME:
|
||||||
|
if ( child == 0 ) {
|
||||||
|
auto& n( (A_FuncNode&) node );
|
||||||
|
return &n.instructions( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Instruction list
|
||||||
|
case A_Node::ILIST: {
|
||||||
|
auto& n( (T_InstrListNode&) node );
|
||||||
|
if ( child < n.size( ) ) {
|
||||||
|
return &n.node( child );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unary operators
|
||||||
|
case A_Node::EXPR_NEG: case A_Node::EXPR_INV:
|
||||||
|
case A_Node::EXPR_NOT: case A_Node::EXPR_SIN:
|
||||||
|
case A_Node::EXPR_COS: case A_Node::EXPR_TAN:
|
||||||
|
case A_Node::EXPR_SQRT: case A_Node::EXPR_EXP:
|
||||||
|
case A_Node::EXPR_LN:
|
||||||
|
{
|
||||||
|
auto& n( (T_UnaryOperatorNode&) node );
|
||||||
|
if ( child == 0 && n.hasArgument( ) ) {
|
||||||
|
return &n.argument( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binary operators
|
||||||
|
case A_Node::EXPR_ADD: case A_Node::EXPR_SUB:
|
||||||
|
case A_Node::EXPR_MUL: case A_Node::EXPR_DIV:
|
||||||
|
case A_Node::EXPR_POW:
|
||||||
|
case A_Node::EXPR_CMP_EQ: case A_Node::EXPR_CMP_NE:
|
||||||
|
case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE:
|
||||||
|
case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE:
|
||||||
|
{
|
||||||
|
auto& n( (T_BinaryOperatorNode&) node );
|
||||||
|
if ( child == 0 && n.hasLeft( ) ) {
|
||||||
|
return &n.left( );
|
||||||
|
}
|
||||||
|
if ( child < 2 && n.hasRight( ) ) {
|
||||||
|
return &n.right( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nodes that do not have children
|
||||||
|
case A_Node::EXPR_ID: case A_Node::EXPR_CONST:
|
||||||
|
case A_Node::OP_PROGRAM: case A_Node::OP_PIPELINE:
|
||||||
|
case A_Node::OP_INPUT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Profile instruction
|
||||||
|
case A_Node::OP_PROFILE:
|
||||||
|
if ( child == 0 ) {
|
||||||
|
return &( ((T_ProfileInstrNode&) node).instructions( ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Call instruction
|
||||||
|
case A_Node::OP_CALL:
|
||||||
|
{
|
||||||
|
auto& n( (T_CallInstrNode&) node );
|
||||||
|
if ( child < n.arguments( ) ) {
|
||||||
|
return &n.argument( child );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conditional instruction
|
||||||
|
case A_Node::OP_COND:
|
||||||
|
{
|
||||||
|
auto& n( (T_CondInstrNode&) node );
|
||||||
|
auto c = child;
|
||||||
|
if ( n.hasExpression( ) ) {
|
||||||
|
if ( c == 0 ) {
|
||||||
|
return &n.expression( );
|
||||||
|
}
|
||||||
|
c --;
|
||||||
|
}
|
||||||
|
if ( !n.cases( ).empty( ) ) {
|
||||||
|
if ( c < n.cases( ).size( ) ) {
|
||||||
|
return &n.getCase( n.cases( )[ c ] );
|
||||||
|
}
|
||||||
|
c -= n.cases( ).size( );
|
||||||
|
}
|
||||||
|
if ( n.hasDefaultCase( ) && c == 0 ) {
|
||||||
|
return &n.defaultCase( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set instruction
|
||||||
|
case A_Node::OP_SET:
|
||||||
|
if ( child == 0 ) {
|
||||||
|
auto& n( (T_SetInstrNode&) node );
|
||||||
|
if ( n.hasExpression( ) ) {
|
||||||
|
return &n.expression( );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Texture instruction
|
||||||
|
case A_Node::OP_TEXTURE:
|
||||||
|
{
|
||||||
|
auto& n( (T_TextureInstrNode&) node );
|
||||||
|
auto c = child;
|
||||||
|
if ( n.hasWidth( ) ) {
|
||||||
|
if ( c == 0 ) {
|
||||||
|
return &n.width( );
|
||||||
|
}
|
||||||
|
c --;
|
||||||
|
}
|
||||||
|
if ( n.hasHeight( ) && c == 0 ) {
|
||||||
|
return &n.height( );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*= A_FuncNode ===============================================================*/
|
/*= A_FuncNode ===============================================================*/
|
||||||
|
|
||||||
|
@ -260,12 +404,23 @@ struct T_ParserImpl_
|
||||||
|
|
||||||
T_OwnPtr< T_RootNode >& root;
|
T_OwnPtr< T_RootNode >& root;
|
||||||
T_Array< T_SRDError >& errors;
|
T_Array< T_SRDError >& errors;
|
||||||
|
T_Visitor< A_Node > visitor{ opast::ASTVisitorBrowser };
|
||||||
|
T_MultiArray< uint32_t > calls;
|
||||||
|
T_Visitor< uint32_t , uint32_t > callGraphVisitor{
|
||||||
|
[this]( uint32_t v , uint32_t child ) -> T_Optional< uint32_t > {
|
||||||
|
const uint32_t nc( calls.sizeOf( v ) );
|
||||||
|
if ( child < nc ) {
|
||||||
|
return calls.get( v , child );
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
} };
|
||||||
|
|
||||||
T_ParserImpl_( T_Array< T_SRDError >* errors ,
|
T_ParserImpl_( T_Array< T_SRDError >* errors ,
|
||||||
T_OwnPtr< T_RootNode >* root ) noexcept;
|
T_OwnPtr< T_RootNode >* root ) noexcept;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
void parseTopLevel( T_SRDList const& list ) noexcept;
|
||||||
void parseFunction( T_SRDList const& funcList ) noexcept;
|
void parseFunction( T_SRDList const& funcList ) noexcept;
|
||||||
void parseFunctionArguments(
|
void parseFunctionArguments(
|
||||||
T_FuncNode& function ,
|
T_FuncNode& function ,
|
||||||
|
@ -317,12 +472,123 @@ struct T_ParserImpl_
|
||||||
T_UnaryOperatorNode::E_Operator op ) noexcept;
|
T_UnaryOperatorNode::E_Operator op ) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
T_ParserImpl_::T_ParserImpl_(
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
inline T_ParserImpl_::T_ParserImpl_(
|
||||||
T_Array< T_SRDError >* const errors ,
|
T_Array< T_SRDError >* const errors ,
|
||||||
T_OwnPtr< T_RootNode >* const root ) noexcept
|
T_OwnPtr< T_RootNode >* const root ) noexcept
|
||||||
: root( *root ) , errors( *errors )
|
: root( *root ) , errors( *errors )
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void T_ParserImpl_::parseTopLevel(
|
||||||
|
T_SRDList const& input ) noexcept
|
||||||
|
{
|
||||||
|
for ( auto const& t : input ) {
|
||||||
|
if ( t.type( ) == E_SRDTokenType::LIST && t.list( ).size( ) > 0 ) {
|
||||||
|
parseFunction( t.list( ) );
|
||||||
|
} else {
|
||||||
|
errors.addNew( "function, init or frame list expected" ,
|
||||||
|
t.location( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !errors.empty( ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T_SRDLocation missingErrLoc( ([&input]() {
|
||||||
|
if ( input.size( ) != 0 ) {
|
||||||
|
return T_SRDLocation( input[ 0 ].location( ).source( ) , 1 , 1 );
|
||||||
|
}
|
||||||
|
return T_SRDLocation{};
|
||||||
|
})( ));
|
||||||
|
if ( !root->hasInit( ) ) {
|
||||||
|
errors.addNew( "no initialisation block" , missingErrLoc );
|
||||||
|
}
|
||||||
|
if ( !root->hasFrame( ) ) {
|
||||||
|
errors.addNew( "no initialisation block" , missingErrLoc );
|
||||||
|
}
|
||||||
|
if ( !errors.empty( ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
calls.clear( );
|
||||||
|
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;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
if ( !errors.empty( ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T_InstrRestriction callInfo[ calls.size( ) ];
|
||||||
|
callGraphVisitor.visit( root->functionIndex( "*init*" ) ,
|
||||||
|
[&]( uint32_t id , const bool exit ) -> bool {
|
||||||
|
if ( exit || callInfo[ id ] & E_InstrRestriction::INIT ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
callInfo[ id ] |= E_InstrRestriction::INIT;
|
||||||
|
return true;
|
||||||
|
} );
|
||||||
|
callGraphVisitor.visit( root->functionIndex( "*frame*" ) ,
|
||||||
|
[&]( uint32_t id , const bool exit ) -> bool {
|
||||||
|
if ( exit || callInfo[ id ] & E_InstrRestriction::FRAME ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void T_ParserImpl_::parseFunction(
|
void T_ParserImpl_::parseFunction(
|
||||||
T_SRDList const& funcList ) noexcept
|
T_SRDList const& funcList ) noexcept
|
||||||
{
|
{
|
||||||
|
@ -829,30 +1095,6 @@ bool T_Parser::parse(
|
||||||
{
|
{
|
||||||
errors_.clear( );
|
errors_.clear( );
|
||||||
rootNode_ = NewOwned< T_RootNode >( );
|
rootNode_ = NewOwned< T_RootNode >( );
|
||||||
|
p< T_ParserImpl_ >( ).parseTopLevel( input );
|
||||||
for ( auto const& t : input ) {
|
|
||||||
if ( t.type( ) == E_SRDTokenType::LIST && t.list( ).size( ) > 0 ) {
|
|
||||||
p< T_ParserImpl_ >( ).parseFunction( t.list( ) );
|
|
||||||
} else {
|
|
||||||
errors_.addNew( "function, init or frame list expected" ,
|
|
||||||
t.location( ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( errors_.empty( ) ) {
|
|
||||||
T_SRDLocation loc( ([&input]() {
|
|
||||||
if ( input.size( ) != 0 ) {
|
|
||||||
return T_SRDLocation( input[ 0 ].location( ).source( ) , 1 , 1 );
|
|
||||||
}
|
|
||||||
return T_SRDLocation{};
|
|
||||||
})( ));
|
|
||||||
if ( !rootNode_->hasInit( ) ) {
|
|
||||||
errors_.addNew( "no initialisation block" , loc );
|
|
||||||
}
|
|
||||||
if ( !rootNode_->hasFrame( ) ) {
|
|
||||||
errors_.addNew( "no initialisation block" , loc );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors_.empty( );
|
return errors_.empty( );
|
||||||
}
|
}
|
||||||
|
|
7
opast.hh
7
opast.hh
|
@ -74,7 +74,12 @@ class A_Node
|
||||||
T_RootNode& root( ) const noexcept;
|
T_RootNode& root( ) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
// Browser function to be used with T_Visitor
|
||||||
|
extern A_Node* ASTVisitorBrowser(
|
||||||
|
A_Node& node ,
|
||||||
|
const uint32_t child ) noexcept;
|
||||||
|
|
||||||
|
/*============================================================================*/
|
||||||
|
|
||||||
// Some instructions are restricted to either the initialisation code or the
|
// Some instructions are restricted to either the initialisation code or the
|
||||||
// frame code.
|
// frame code.
|
||||||
|
|
274
parsercheck.cc
274
parsercheck.cc
|
@ -2,7 +2,6 @@
|
||||||
#include "opast.hh"
|
#include "opast.hh"
|
||||||
#include <ebcl/Files.hh>
|
#include <ebcl/Files.hh>
|
||||||
#include <ebcl/SRDText.hh>
|
#include <ebcl/SRDText.hh>
|
||||||
#include <ebcl/Algorithms.hh>
|
|
||||||
|
|
||||||
using namespace ebcl;
|
using namespace ebcl;
|
||||||
using namespace opast;
|
using namespace opast;
|
||||||
|
@ -35,277 +34,7 @@ void WriteSRDError(
|
||||||
|
|
||||||
|
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
// FIXME TESTING, MOVE THIS LATER
|
|
||||||
|
|
||||||
A_Node* OpASTBrowser(
|
|
||||||
A_Node& node ,
|
|
||||||
const uint32_t child )
|
|
||||||
{
|
|
||||||
switch ( node.type( ) ) {
|
|
||||||
|
|
||||||
// Root node
|
|
||||||
case A_Node::ROOT: {
|
|
||||||
auto& n( (T_RootNode&) node );
|
|
||||||
if ( child < n.nFunctions( ) ) {
|
|
||||||
return &n.function( child );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions / special blocks
|
|
||||||
case A_Node::DECL_FN: case A_Node::DECL_INIT: case A_Node::DECL_FRAME:
|
|
||||||
if ( child == 0 ) {
|
|
||||||
auto& n( (A_FuncNode&) node );
|
|
||||||
return &n.instructions( );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Instruction list
|
|
||||||
case A_Node::ILIST: {
|
|
||||||
auto& n( (T_InstrListNode&) node );
|
|
||||||
if ( child < n.size( ) ) {
|
|
||||||
return &n.node( child );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unary operators
|
|
||||||
case A_Node::EXPR_NEG: case A_Node::EXPR_INV:
|
|
||||||
case A_Node::EXPR_NOT: case A_Node::EXPR_SIN:
|
|
||||||
case A_Node::EXPR_COS: case A_Node::EXPR_TAN:
|
|
||||||
case A_Node::EXPR_SQRT: case A_Node::EXPR_EXP:
|
|
||||||
case A_Node::EXPR_LN:
|
|
||||||
{
|
|
||||||
auto& n( (T_UnaryOperatorNode&) node );
|
|
||||||
if ( child == 0 && n.hasArgument( ) ) {
|
|
||||||
return &n.argument( );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Binary operators
|
|
||||||
case A_Node::EXPR_ADD: case A_Node::EXPR_SUB:
|
|
||||||
case A_Node::EXPR_MUL: case A_Node::EXPR_DIV:
|
|
||||||
case A_Node::EXPR_POW:
|
|
||||||
case A_Node::EXPR_CMP_EQ: case A_Node::EXPR_CMP_NE:
|
|
||||||
case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE:
|
|
||||||
case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE:
|
|
||||||
{
|
|
||||||
auto& n( (T_BinaryOperatorNode&) node );
|
|
||||||
if ( child == 0 && n.hasLeft( ) ) {
|
|
||||||
return &n.left( );
|
|
||||||
}
|
|
||||||
if ( child < 2 && n.hasRight( ) ) {
|
|
||||||
return &n.right( );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nodes that do not have children
|
|
||||||
case A_Node::EXPR_ID: case A_Node::EXPR_CONST:
|
|
||||||
case A_Node::OP_PROGRAM: case A_Node::OP_PIPELINE:
|
|
||||||
case A_Node::OP_INPUT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Profile instruction
|
|
||||||
case A_Node::OP_PROFILE:
|
|
||||||
if ( child == 0 ) {
|
|
||||||
return &( ((T_ProfileInstrNode&) node).instructions( ) );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Call instruction
|
|
||||||
case A_Node::OP_CALL:
|
|
||||||
{
|
|
||||||
auto& n( (T_CallInstrNode&) node );
|
|
||||||
if ( child < n.arguments( ) ) {
|
|
||||||
return &n.argument( child );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conditional instruction
|
|
||||||
case A_Node::OP_COND:
|
|
||||||
{
|
|
||||||
auto& n( (T_CondInstrNode&) node );
|
|
||||||
auto c = child;
|
|
||||||
if ( n.hasExpression( ) ) {
|
|
||||||
if ( c == 0 ) {
|
|
||||||
return &n.expression( );
|
|
||||||
}
|
|
||||||
c --;
|
|
||||||
}
|
|
||||||
if ( !n.cases( ).empty( ) ) {
|
|
||||||
if ( c < n.cases( ).size( ) ) {
|
|
||||||
return &n.getCase( n.cases( )[ c ] );
|
|
||||||
}
|
|
||||||
c -= n.cases( ).size( );
|
|
||||||
}
|
|
||||||
if ( n.hasDefaultCase( ) && c == 0 ) {
|
|
||||||
return &n.defaultCase( );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set instruction
|
|
||||||
case A_Node::OP_SET:
|
|
||||||
if ( child == 0 ) {
|
|
||||||
auto& n( (T_SetInstrNode&) node );
|
|
||||||
if ( n.hasExpression( ) ) {
|
|
||||||
return &n.expression( );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Texture instruction
|
|
||||||
case A_Node::OP_TEXTURE:
|
|
||||||
{
|
|
||||||
auto& n( (T_TextureInstrNode&) node );
|
|
||||||
auto c = child;
|
|
||||||
if ( n.hasWidth( ) ) {
|
|
||||||
if ( c == 0 ) {
|
|
||||||
return &n.width( );
|
|
||||||
}
|
|
||||||
c --;
|
|
||||||
}
|
|
||||||
if ( n.hasHeight( ) && c == 0 ) {
|
|
||||||
return &n.height( );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool checkCalls( T_RootNode& root )
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
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 , uint32_t > callGraphVisitor(
|
|
||||||
[&]( uint32_t v , uint32_t child ) -> T_Optional< uint32_t > {
|
|
||||||
const uint32_t nc( calls.sizeOf( v ) );
|
|
||||||
if ( child < nc ) {
|
|
||||||
return calls.get( v , child );
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
} );
|
|
||||||
T_InstrRestriction callInfo[ calls.size( ) ];
|
|
||||||
|
|
||||||
callGraphVisitor.visit( root.functionIndex( "*init*" ) ,
|
|
||||||
[&]( uint32_t id , const bool exit ) -> bool {
|
|
||||||
if ( exit || callInfo[ id ] & E_InstrRestriction::INIT ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
callInfo[ id ] |= E_InstrRestriction::INIT;
|
|
||||||
return true;
|
|
||||||
} );
|
|
||||||
callGraphVisitor.visit( root.functionIndex( "*frame*" ) ,
|
|
||||||
[&]( uint32_t id , const bool exit ) -> bool {
|
|
||||||
if ( exit || callInfo[ id ] & E_InstrRestriction::FRAME ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
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 ) );
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*============================================================================*/
|
/*============================================================================*/
|
||||||
|
|
||||||
|
@ -348,9 +77,6 @@ int main( int argc , char** argv )
|
||||||
T_Parser parser;
|
T_Parser parser;
|
||||||
if ( parser.parse( srdOut.list( ) ) ) {
|
if ( parser.parse( srdOut.list( ) ) ) {
|
||||||
printf( "Success!\n" );
|
printf( "Success!\n" );
|
||||||
|
|
||||||
auto result( parser.result( ) );
|
|
||||||
checkCalls( *result );
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
T_StringBuilder sb;
|
T_StringBuilder sb;
|
||||||
|
|
Loading…
Reference in a new issue