What a good way to handle inline functions in an interpreter written in C ++?

I am writing an interpreter in C ++ for the lisp-like language of my humble design. This is for pleasure and learning, so I have not achieved absolute effectiveness. But I'm trying to have very clean C ++ code. I am now wondering how to implement the built-in functions.

Basically what I do:

I have an abstract base class DataObject that simply provides type information (currently double, int, bool) and is inherited by specific data containers, for example:

class DataObject
{
public:
    virtual const Type *type() = 0;
};

template<class T, const Type * myType>
class DataObjectValue : public DataObject
{
T value;
public:
    const Type *type(){return myType;}
};

But then, when I want to complete the addition, I have to do things like:

DataObject * sum(DataObject *a, DataObject *b)
{
    if(a->type() == &Integer and b->type == &Integer)
    {
        DataObjectValue<int>* ia = dynamic_cast< DataObjectValue<int>* >(a);
        DataObjectValue<int>* ib = dynamic_cast< DataObjectValue<int>* >(b);
        return new DataObjectValue<int>(ia->value+ib->value);
    }
    else if(a->type() == &Real and b->type == &Real)
    {
        DataObjectValue<double>* ra = dynamic_cast< DataObjectValue<double>* >(a);
        DataObjectValue<double>* rb = dynamic_cast< DataObjectValue<double>* >(b);
        return new DataObjectValue<double>(ra->value+rb->value);
    }
    else...
}

( - */< = lt; = >= < > ....) . . , , , , , . a) , ( , , ) b) - ?

+5
3

, , , ( , ?)

:

enum DataType {
   type_bool,
   type_int,
   type_double
};

struct DataObject {
   virtual ~DataObject() {}    // remember to provide a virtual destructor if you
                               // intend on deleting through base pointers!!!
   virtual DataType type() const = 0;
   virtual bool   asBool() const = 0;
   virtual int    asInt() const = 0;
   virtual double asDouble() const = 0;
};

:

template <typename T>
T sum_impl( T lhs, T rhs ) {
   return lhs + rhs;
}

:

DataType promoteTypes( DataType lhs, DataType rhs ) {
   if ( lhs == type_double || rhs == type_double ) {
      return type_double;
   } else if ( lhs == type_int || rhs == type_int ) {
      return type_int;
   } else {
      return type_bool;
   }
}
template <template <typename T> T operation (T,T)>
DataObject* perform_operation( DataObject* lhs, DataObject* rhs, operation op ) const {
   DataType result_type = promoteTypes( lhs->type(), rhs->type() );
   switch ( result_type ) {
   case type_double: 
      return new DataObjectValue<double>( op( lhs->asDouble(), rhs->asDouble() );
   case type_int:
      return new DataObjectValue<int>( op( lhs->asInt(), rhs->asInt() );
   case type_bool:
      return new DataObjectValue<bool>( op( lhs->asBool(), rhs->asBool() );
   default:
      abort();
   }
}

, ( sum ), :

// sum_impl as above
DataObject* sum( DataObject* lhs, DataObject* rhs ) {
   return perform_operation( lhs, rhs, sum_impl );
}

, , , , , , . , ( boost any) Object , DataObject, ( ). , ( , , Object ). .

+3

aproach:

( \ )

#define IMPLEMENT_OPERATOR(name, operator)
DataObject * name(DataObject *a, DataObject *b)
{
    if(a->type() == &Integer and b->type == &Integer)
    {
        DataObjectValue<int>* ia = dynamic_cast< DataObjectValue<int>* >(a);
        DataObjectValue<int>* ib = dynamic_cast< DataObjectValue<int>* >(b);
        return new DataObjectValue<int>(ia->value operator ib->value);
    }
    else if(a->type() == &Real and b->type == &Real)
    {
        DataObjectValue<double>* ra = dynamic_cast< DataObjectValue<double>* >(a);
        DataObjectValue<double>* rb = dynamic_cast< DataObjectValue<double>* >(b);
        return new DataObjectValue<double>(ra->value operator rb->value);
    }
    else...
}

, :

IMPLEMENT_OPERATOR(sum, +);
IMPLEMENT_OPERATOR(multiply, *);
IMPLEMENT_OPERATOR(division, /);
...

, .

EDIT: , . .

( , \ )

#define IMPLEMENT_OPERATOR_TYPE(typeobject, internal_type, operator)
if(a->type() == &typeobject and b->type == &typeobject)
{
    DataObjectValue<internal_type>* ia = dynamic_cast< DataObjectValue<internal_type>* >(a);
    DataObjectValue<internal_type>* ib = dynamic_cast< DataObjectValue<internal_type>* >(b);
    return new DataObjectValue<internal_type>(ia->value operator ib->value);
}

IMPLEMENT_OPERATOR:

#define IMPLEMENT_OPERATOR(name, operator)
DataObject * name(DataObject *a, DataObject *b)
{
    IMPLEMENT_OPERATOR_TYPE(&Integer, int, operator);
    IMPLEMENT_OPERATOR_TYPE(&Real, double, operator);
    ...
}
+1

, :

class DataObject
{
public:
    virtual const Type *type() = 0;
    virtual DataObject *operator+(DataObject&) = 0;
    virtual DataObject *operator-(DataObject&) = 0;
    virtual DataObject *operator*(DataObject&) = 0;
    virtual DataObject *operator/(DataObject&) = 0;
};

template<class T, const Type * myType>
class DataObjectValue : public DataObject
{
    typedef DataObjectValue<T, myType> selfType;
    T value;
public:
    const Type *type(){return myType;}
    DataObject *operator+(DataObject& other) {
        if (other.type() != myType)
            return null;
        selfType &otherValue = static_cast<selfType&>(other);
        return new selfType(value + otherValue.value);
    }
    // etc.
};

, int + double. , , (.. ), :

if (other.type() != myType)
    return other + *this; // assume *other is a <double> that knows how to add an <int>
+1

All Articles