Syntax tree - Added basic abstraction
This commit is contained in:
parent
7b97993448
commit
a9762a901e
4 changed files with 359 additions and 0 deletions
119
include/ebcl/SyntaxTree.hh
Normal file
119
include/ebcl/SyntaxTree.hh
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/******************************************************************************/
|
||||||
|
/* ABSTRACT SYNTAX TREE *******************************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _H_EBCL_SYNTAXTREE
|
||||||
|
#define _H_EBCL_SYNTAXTREE
|
||||||
|
#include <ebcl/Types.hh>
|
||||||
|
#include <ebcl/Arrays.hh>
|
||||||
|
namespace ebcl {
|
||||||
|
|
||||||
|
|
||||||
|
/*= SYNTAX TREE ==============================================================*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A syntax tree has typed nodes; each nodes may have 0, 1 or more children
|
||||||
|
* of various types. In addition, a node may carry additional data. The type
|
||||||
|
* of the data associated to a given node is not known.
|
||||||
|
*
|
||||||
|
* Nodes are accessed using integer indices. The tree's root node is always at
|
||||||
|
* index 0.
|
||||||
|
*/
|
||||||
|
template<
|
||||||
|
// Node type (should be an enum)
|
||||||
|
typename NodeType ,
|
||||||
|
// Data storage size
|
||||||
|
size_t InPlaceSize = sizeof( void* )
|
||||||
|
> class T_SyntaxTree
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using E_Node = NodeType;
|
||||||
|
using T_Self = T_SyntaxTree< NodeType , InPlaceSize >;
|
||||||
|
static constexpr size_t StorageSize
|
||||||
|
= T_VariantExt< InPlaceSize >::StorageSize;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct T_Node_
|
||||||
|
{
|
||||||
|
// Node type
|
||||||
|
E_Node type;
|
||||||
|
// Index of the parent node
|
||||||
|
uint32_t parent;
|
||||||
|
// Indices of the node's children
|
||||||
|
T_AutoArray< uint32_t , 8 > children;
|
||||||
|
// Extra data storage
|
||||||
|
T_VariantExt< StorageSize > data;
|
||||||
|
|
||||||
|
explicit T_Node_( E_Node type ,
|
||||||
|
uint32_t parent ) noexcept;
|
||||||
|
|
||||||
|
T_Node_( T_Node_ const& ) = delete;
|
||||||
|
T_Node_& operator =( T_Node_ const& ) = delete;
|
||||||
|
|
||||||
|
T_Node_( T_Node_&& other ) noexcept;
|
||||||
|
T_Node_& operator =( T_Node_&& other ) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
T_Array< T_Node_ > nodes_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
M_TEMPLATE_POINTERS( T_SyntaxTree );
|
||||||
|
|
||||||
|
// Create the syntax tree, specifying the type of the root node
|
||||||
|
explicit T_SyntaxTree( E_Node rootType ) noexcept;
|
||||||
|
|
||||||
|
// Copy is disabled
|
||||||
|
T_SyntaxTree( T_Self const& ) = delete;
|
||||||
|
T_Self& operator =( T_Self const& other ) = delete;
|
||||||
|
|
||||||
|
// Move construction / assignment
|
||||||
|
T_SyntaxTree( T_Self&& other ) noexcept;
|
||||||
|
T_Self& operator =( T_Self&& other ) noexcept;
|
||||||
|
|
||||||
|
// Swapping
|
||||||
|
T_Self& swap( T_Self& other ) noexcept;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Get the type of a node
|
||||||
|
E_Node typeOf( uint32_t node ) const noexcept;
|
||||||
|
|
||||||
|
// Returns the index of a node's parent. The root node will always
|
||||||
|
// return its own index.
|
||||||
|
uint32_t parentOf( uint32_t node ) const noexcept;
|
||||||
|
|
||||||
|
// Access the list of children for a node
|
||||||
|
T_AutoArray< uint32_t , 8 > const& childrenOf(
|
||||||
|
uint32_t node ) const noexcept;
|
||||||
|
|
||||||
|
// Check whether some node contains data
|
||||||
|
bool hasData( uint32_t node ) const noexcept;
|
||||||
|
|
||||||
|
// Access the data stored inside a node
|
||||||
|
template< typename D >
|
||||||
|
D const& dataOf( uint32_t node ) const;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Add a new child, return its index
|
||||||
|
uint32_t addChild(
|
||||||
|
uint32_t parent ,
|
||||||
|
E_Node type ) noexcept;
|
||||||
|
|
||||||
|
// Add data to a node
|
||||||
|
template< typename D , typename ... Args >
|
||||||
|
D& newData( uint32_t node , Args&& ... args );
|
||||||
|
|
||||||
|
// Access the data stored inside a node
|
||||||
|
template< typename D >
|
||||||
|
D& dataOf( uint32_t node );
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
void swap( T_SyntaxTree< T , S >& lhs , T_SyntaxTree< T , S >& rhs ) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // _H_EBCL_SYNTAXTREE
|
||||||
|
#include <ebcl/inline/SyntaxTree.hh>
|
162
include/ebcl/inline/SyntaxTree.hh
Normal file
162
include/ebcl/inline/SyntaxTree.hh
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/******************************************************************************/
|
||||||
|
/* ABSTRACT SYNTAX TREE - INLINE CODE******************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _H_EBCL_INLINE_SYNTAXTREE
|
||||||
|
#define _H_EBCL_INLINE_SYNTAXTREE
|
||||||
|
#include <ebcl/SyntaxTree.hh>
|
||||||
|
namespace ebcl {
|
||||||
|
|
||||||
|
|
||||||
|
/*= T_SyntaxTree =============================================================*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_Node_::T_Node_(
|
||||||
|
const T nodeType ,
|
||||||
|
const uint32_t parent ) noexcept
|
||||||
|
: type{ nodeType } , parent{ parent }
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_Node_::T_Node_(
|
||||||
|
T_Node_&& other ) noexcept
|
||||||
|
: type{ other.type } , parent{ other.parent } ,
|
||||||
|
children{ std::move( other.children ) } ,
|
||||||
|
data{ std::move( other.data ) }
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
typename T_SyntaxTree< T , S >::T_Node_& T_SyntaxTree< T , S >::T_Node_::operator =(
|
||||||
|
T_Node_&& other ) noexcept
|
||||||
|
{
|
||||||
|
type = other.type;
|
||||||
|
parent = other.parent;
|
||||||
|
children = std::move( other.children );
|
||||||
|
data = std::move( other.data );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_SyntaxTree(
|
||||||
|
const T rootType ) noexcept
|
||||||
|
: nodes_( 64 )
|
||||||
|
{
|
||||||
|
nodes_.addNew( rootType , 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >::T_SyntaxTree(
|
||||||
|
T_SyntaxTree< T , S >&& other ) noexcept
|
||||||
|
: nodes_{ std::move( other.nodes_ ) }
|
||||||
|
{
|
||||||
|
// EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >& T_SyntaxTree< T , S >::operator =(
|
||||||
|
T_SyntaxTree< T , S >&& other ) noexcept
|
||||||
|
{
|
||||||
|
nodes_ = std::move( other.nodes_ );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_SyntaxTree< T , S >& T_SyntaxTree< T , S >::swap(
|
||||||
|
T_SyntaxTree< T , S >& other ) noexcept
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
swap( nodes_ , other.nodes_ );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
void swap( T_SyntaxTree< T , S >& lhs ,
|
||||||
|
T_SyntaxTree< T , S >& rhs ) noexcept
|
||||||
|
{
|
||||||
|
lhs.swap( rhs );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T T_SyntaxTree< T , S >::typeOf(
|
||||||
|
const uint32_t node ) const noexcept
|
||||||
|
{
|
||||||
|
return nodes_[ node ].type;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
uint32_t T_SyntaxTree< T , S >::parentOf(
|
||||||
|
const uint32_t node ) const noexcept
|
||||||
|
{
|
||||||
|
return nodes_[ node ].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
T_AutoArray< uint32_t , 8 > const& T_SyntaxTree< T , S >::childrenOf(
|
||||||
|
const uint32_t node ) const noexcept
|
||||||
|
{
|
||||||
|
return nodes_[ node ].children;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
bool T_SyntaxTree< T , S >::hasData(
|
||||||
|
const uint32_t node ) const noexcept
|
||||||
|
{
|
||||||
|
return bool( nodes_[ node ].data );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
template< typename D >
|
||||||
|
D const& T_SyntaxTree< T , S >::dataOf(
|
||||||
|
const uint32_t node ) const
|
||||||
|
{
|
||||||
|
return nodes_[ node ].data.template value< D >( );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
uint32_t T_SyntaxTree< T , S >::addChild(
|
||||||
|
const uint32_t parent ,
|
||||||
|
const E_Node type ) noexcept
|
||||||
|
{
|
||||||
|
T_Node_ node{ type , parent };
|
||||||
|
const auto idx{ nodes_.add( std::move( node ) ) };
|
||||||
|
assert( idx != parent );
|
||||||
|
nodes_[ parent ].children.add( idx );
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
template< typename D , typename ... ArgTypes >
|
||||||
|
D& T_SyntaxTree< T , S >::newData(
|
||||||
|
const uint32_t node ,
|
||||||
|
ArgTypes&& ... args )
|
||||||
|
{
|
||||||
|
auto& data{ nodes_[ node ].data };
|
||||||
|
data.template setNew< D >( std::forward< ArgTypes >( args ) ... );
|
||||||
|
return data.template value< D >( );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< typename T , size_t S >
|
||||||
|
template< typename D >
|
||||||
|
D& T_SyntaxTree< T , S >::dataOf(
|
||||||
|
const uint32_t node )
|
||||||
|
{
|
||||||
|
return nodes_[ node ].data.template value< D >( );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
#endif // _H_EBCL_INLINE_SYNTAXTREE
|
|
@ -33,4 +33,5 @@ TESTS = \
|
||||||
srd-parser-defs \
|
srd-parser-defs \
|
||||||
srd-parser-cfg \
|
srd-parser-cfg \
|
||||||
srd-parser \
|
srd-parser \
|
||||||
|
syntax-tree \
|
||||||
# END
|
# END
|
||||||
|
|
77
tests/syntax-tree.cc
Normal file
77
tests/syntax-tree.cc
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <ebcl/SyntaxTree.hh>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
using namespace ebcl;
|
||||||
|
|
||||||
|
class SyntaxTreeTest : public CppUnit::TestFixture
|
||||||
|
{
|
||||||
|
CPPUNIT_TEST_SUITE( SyntaxTreeTest );
|
||||||
|
CPPUNIT_TEST( testEmpty );
|
||||||
|
CPPUNIT_TEST( testSetData );
|
||||||
|
CPPUNIT_TEST( testUpdateData );
|
||||||
|
CPPUNIT_TEST( testAddChildren );
|
||||||
|
CPPUNIT_TEST_SUITE_END( );
|
||||||
|
|
||||||
|
public:
|
||||||
|
void testEmpty( );
|
||||||
|
void testSetData( );
|
||||||
|
void testUpdateData( );
|
||||||
|
void testAddChildren( );
|
||||||
|
};
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION( SyntaxTreeTest );
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
enum class E_TestNode_
|
||||||
|
{
|
||||||
|
ROOT ,
|
||||||
|
ADD ,
|
||||||
|
VALUE
|
||||||
|
};
|
||||||
|
|
||||||
|
using T_Test_ = T_SyntaxTree< E_TestNode_ >;
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void SyntaxTreeTest::testEmpty( )
|
||||||
|
{
|
||||||
|
T_Test_ st{ E_TestNode_::ROOT };
|
||||||
|
CPPUNIT_ASSERT( E_TestNode_::ROOT == st.typeOf( 0 ) );
|
||||||
|
CPPUNIT_ASSERT( st.childrenOf( 0 ).empty( ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 0u , st.parentOf( 0 ) );
|
||||||
|
CPPUNIT_ASSERT( !st.hasData( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyntaxTreeTest::testSetData( )
|
||||||
|
{
|
||||||
|
T_Test_ st{ E_TestNode_::ROOT };
|
||||||
|
CPPUNIT_ASSERT( E_TestNode_::ROOT == st.typeOf( 0 ) );
|
||||||
|
CPPUNIT_ASSERT( !st.hasData( 0 ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 12u , st.newData< uint32_t >( 0 , 12 ) );
|
||||||
|
CPPUNIT_ASSERT( st.hasData( 0 ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 12u , st.dataOf< uint32_t>( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyntaxTreeTest::testUpdateData( )
|
||||||
|
{
|
||||||
|
T_Test_ st{ E_TestNode_::ROOT };
|
||||||
|
st.newData< uint32_t >( 0 , 12 );
|
||||||
|
st.dataOf< uint32_t>( 0 ) = 42u;
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 42u , st.dataOf< uint32_t>( 0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SyntaxTreeTest::testAddChildren( )
|
||||||
|
{
|
||||||
|
T_Test_ st{ E_TestNode_::ROOT };
|
||||||
|
const auto rc{ st.addChild( 0 , E_TestNode_::ADD ) };
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 1u , rc );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 1u , st.childrenOf( 0 ).size( ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( rc , st.childrenOf( 0 )[ 0 ] );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 0u , st.parentOf( rc ) );
|
||||||
|
CPPUNIT_ASSERT( E_TestNode_::ADD == st.typeOf( rc ) );
|
||||||
|
|
||||||
|
const auto cc{ st.addChild( rc , E_TestNode_::VALUE ) };
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 2u , cc );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( 1u , st.childrenOf( rc ).size( ) );
|
||||||
|
CPPUNIT_ASSERT_EQUAL( cc , st.childrenOf( rc )[ 0 ] );
|
||||||
|
CPPUNIT_ASSERT( E_TestNode_::VALUE == st.typeOf( cc ) );
|
||||||
|
}
|
Loading…
Reference in a new issue