diff --git a/opast.hh b/opast.hh index bdf5016..4844cc3 100644 --- a/opast.hh +++ b/opast.hh @@ -99,6 +99,11 @@ class T_InstrListNode : public A_Node typename IType , typename... ArgTypes > IType& add( ArgTypes&&... args ); + + uint32_t size( ) const noexcept + { return instructions_.size( ); } + A_InstructionNode& node( const uint32_t index ) const noexcept + { return *instructions_[ index ]; } }; template< @@ -189,6 +194,11 @@ class T_RootNode : public A_Node { return hasFunction( "*init*" ); } bool hasFrame( ) noexcept { return hasFunction( "*frame*" ); } + + uint32_t nFunctions( ) const noexcept + { return functions_.size( ); } + A_FuncNode& function( const uint32_t index ) const noexcept + { return *functions_.values( )[ index ]; } }; /*----------------------------------------------------------------------------*/ diff --git a/parsercheck.cc b/parsercheck.cc index 6da818a..d085b16 100644 --- a/parsercheck.cc +++ b/parsercheck.cc @@ -8,6 +8,232 @@ using namespace opast; namespace { +/*============================================================================*/ +// FIXME TESTING, MOVE THIS LATER + +template< typename NodeType > +class T_Visitor +{ + public: + using T_Node = NodeType; + + // Node browser. Returns the Nth child of the specified node, or null + // if there are no children left. + using F_NodeBrowser = std::function< T_Node*( T_Node& , uint32_t ) >; + + // Node action. Second parameter indicates whether the action is + // being called before (false) or after (true) visiting the children. + using F_NodeAction = std::function< bool( T_Node& , bool ) >; + + private: + enum E_State_ { + BEFORE , CHILDREN , AFTER + }; + struct T_NodeRef_ { + T_Node* node; + uint32_t child; + E_State_ state{ BEFORE }; + + explicit T_NodeRef_( T_Node* node ) + : node( node ) , child( 0 ) {} + explicit T_NodeRef_( T_Node* node , uint32_t child ) + : node( node ) , child( child ) {} + }; + + F_NodeBrowser nodeBrowser_; + T_Array< T_NodeRef_ > stack_; + + public: + T_Visitor( ) = delete; + T_Visitor( T_Visitor const& ) noexcept = default; + T_Visitor( T_Visitor&& ) noexcept = default; + + explicit T_Visitor( F_NodeBrowser browser ) noexcept; + + void visit( T_Node& root , F_NodeAction action ); +}; + +template< typename T > +inline T_Visitor< T >::T_Visitor( + F_NodeBrowser browser ) noexcept + : nodeBrowser_( std::move( browser ) ) +{ } + +template< typename T > +inline void T_Visitor< T >::visit( + T_Node& root , + F_NodeAction action ) +{ + stack_.addNew( &root , 0 ); + + while ( !stack_.empty( ) ) { + auto& n( stack_.last( ) ); + switch ( n.state ) { + case BEFORE: + n.state = action( *n.node , false ) ? CHILDREN : AFTER; + break; + case CHILDREN: { + T_Node* child( nodeBrowser_( *n.node , n.child ++ ) ); + if ( child ) { + stack_.addNew( child , 0 ); + } else { + n.state = AFTER; + } + break; + } + case AFTER: + action( *n.node , true ); + stack_.removeLast( ); + break; + } + } +} + +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; +} + + +/*============================================================================*/ + + void PrintStreamError( char const* const prefix , T_String const& name , @@ -69,6 +295,15 @@ int main( int argc , char** argv ) T_Parser parser; if ( parser.parse( srdOut.list( ) ) ) { printf( "Success!\n" ); + + auto result( parser.result( ) ); + T_Visitor< A_Node > visitor( OpASTBrowser ); + visitor.visit( *result , []( A_Node& node , bool enter ) { + if ( enter ) { + printf( "Enter node %p\n" , &node ); + } + return true; + } ); return 0; } else { T_StringBuilder sb;