#include <unordered_map>
#include <functional>
#include <sstream>
#include <cctype>
#include <stack>
#include <utility>
#include <type_traits>
#include <tuple>
#include <concepts>
#include <memory>
#include <iostream>
#include <cstdlib>
#include <new>
#include <limits>
#include <iomanip>
template < class Ty >
struct Mallocator{
using propagate_on_container_copy_assignment = std::true_type;
typedef ::std::decay_t< Ty > value_type;
typedef ::std::add_pointer< value_type >::type pointer;
typedef ::std::size_t size_type;
::std::allocator<value_type> allocator;
Mallocator( void ) = default;
template < class U >
explicit constexpr Mallocator ( const Mallocator < U >& ) noexcept{}
pointer allocate( size_type n ){
if( n > ::std::numeric_limits< size_type >::max() / sizeof( value_type ) )
throw ::std::bad_array_new_length();
if( auto p = static_cast< pointer >( ::std::malloc( n * sizeof( value_type ) ) ) ){
report( p, n );
return p;
}
throw ::std::bad_alloc();
}
void deallocate( pointer p, size_type n ) noexcept{
report( p, n, 0 );
::std::free( p );
}
template <typename U>
void destroy(U* p) {
::std::allocator_traits<std::allocator<Ty>>::destroy(allocator, p);
}
template <typename U>
using rebind = Mallocator<U>;
private:
void report( pointer p, size_type n, bool alloc = true ) const{
::std::cout << ::std::hex << ::std::showbase
<< reinterpret_cast< void * >( p )
<< ::std::dec
<< (alloc ? "alloc": "dealloc")
<< sizeof( value_type ) * n
<< "bytes";
::std::endl( ::std::cout );
}
};
template < class T, class U >
inline constexpr
bool operator==( const Mallocator <T>&, const Mallocator <U>& ) { return true; }
template < class T, class U >
inline constexpr
bool operator!=( const Mallocator <T>&, const Mallocator <U>& ) { return false; }
class expression{
public:
virtual ~expression( void ) {}
virtual int interprete( ::std::unordered_map< char, int >& map ) const = 0;
};
using abstr_expr_uptr =
::std::unique_ptr< expression, Mallocator< expression > >;
class variable : public expression{
protected: char key;
public:
variable( const char& key ) : key( key ) {}
inline virtual
int interprete( ::std::unordered_map< char, int >& assign_map ) const {
return assign_map[ key ];
}
};
class arthmetic : public expression{
protected:
abstr_expr_uptr lopd, ropd;
private: ::std::function< int( int, int ) > f;
public:
template < class Callable ,
class = typename ::std::enable_if_t<
::std::is_same_v<
int, typename ::std::result_of<
Callable&&( int, int ) >::type > > >
requires ::std::regular_invocable< Callable, int , int >
arthmetic( abstr_expr_uptr lopd,
abstr_expr_uptr ropd,
Callable&& f )
:lopd( std::move( lopd ) )
,ropd( std::move( ropd ) )
,f( ::std::forward< ::std::decay_t< Callable > >( f ) ) {}
inline virtual
int interprete( ::std::unordered_map< char, int >& assign_map ) const override{
return ::std::invoke( f, lopd->interprete( assign_map ), ropd->interprete( assign_map ) );
}
};
::std::unordered_map< char, int >
arthmetic_priority_map( { {'+', 0},
{'-', 1},
{'*', 2},
{'/', 3} } );
template < typename Ty >
Ty get( ::std::stack< Ty >& Stk ){
if( !Stk.empty() ){
Ty result = std::move( Stk.top() );
Stk.pop();
return ::std::move( result );
}
}
class factory{
public:
static abstr_expr_uptr
create_arthmetic( char oper,
abstr_expr_uptr lopd,
abstr_expr_uptr ropd ){
switch( oper ){
case '+': return abstr_expr_uptr(new arthmetic( ::std::move( lopd ), ::std::move( ropd ), [](int v1, int v2)->int{ return v1 + v2; } ) );
case '-': return abstr_expr_uptr(new arthmetic( ::std::move( lopd ), ::std::move( ropd ), [](int v1, int v2)->int{ return v1 - v2; } ) );
case '*': return abstr_expr_uptr(new arthmetic( ::std::move( lopd ), ::std::move( ropd ), [](int v1, int v2)->int{ return v1 * v2; } ) );
case '/': return abstr_expr_uptr(new arthmetic( ::std::move( lopd ), ::std::move( ropd ), [](int v1, int v2)->int{ return v1 / v2; } ) );
default: return nullptr;
}
}
static abstr_expr_uptr
create_variable( char var ){
return abstr_expr_uptr( new variable( var ) );
}
};
abstr_expr_uptr analyse( ::std::istringstream& out ){
char _Char { 0 };
::std::stack< abstr_expr_uptr > variableStack;
::std::stack< char > arthmeticStack;
while( (bool)out.get( _Char ) ){
if( ::std::isalpha( _Char ) )
variableStack.push( factory::create_variable( _Char ) );
else if ( _Char == '(' ) variableStack.push( analyse( out ) );
else if( _Char == ')' ) {
while( !arthmeticStack.empty() )
variableStack.push( factory::create_arthmetic( get( arthmeticStack ), get( variableStack ), get( variableStack ) ) );
return ::std::move( variableStack.top() );
}else{
while( ! arthmeticStack.empty()
&& arthmetic_priority_map[ _Char ]
< arthmetic_priority_map[ arthmeticStack.top() ] )
variableStack.push( factory::create_arthmetic( get( arthmeticStack ), get( variableStack ), get( variableStack ) ) );
arthmeticStack.push( _Char );
}
}
while( !arthmeticStack.empty() )
variableStack.push( factory::create_arthmetic( get( arthmeticStack ), get( variableStack ), get( variableStack ) ) );
return ::std::move( variableStack.top() );
}
int main( void ){
::std::unordered_map< char, int > assign_map( { {'a',1},{'b',2},{'c',3} } );
::std::string expr {"a+(a+b)*c"};
::std::istringstream in( expr );
abstr_expr_uptr exprTree =
::std::move( analyse( in ) );
::std::cout << expr << " = " << exprTree->interprete( assign_map );
::std::endl( ::std::cout );
return 0;
}