views:

87

answers:

3

I have managed to write several interpreters including

  • Tokenizing
  • Parsing, including more complicated expressions such as ((x+y)*z)/2
  • Building bytecode from syntax trees
  • Actual bytecode execution

What I didn't manage: Implementation of dictionaries/lists/arrays.

I always got stuck with getting multiple values into one variable.

My value structure (used for all values passed around, including variables) looks like this, for example:

class Value
{
public:
 ValueType type;

 int integerValue;
 string stringValue;
}

Works fine with integers and strings, but how could I implement arrays?

(From now on with array I mean arrays in my experimental language, not in C++)

  • How can I fit the array concept into the Value class above? Is it possible?

  • How should I make arrays able to be passed around just as you could pass around integers and strings in my language, using the class above?

Accessing array elements or memory allocation wouldn't be the problem, I just don't know how to store them.

+2  A: 

If I do this, does the rest follow through easily enough?

class Value
{
public:
 ValueType type;

 int integerValue;
 string stringValue;
 vector<Value> arrayValue;
}
glowcoder
Doesn't this result in some sort of recursive problem?
Ray
Not at all. The vector is initially empty, so the `arrayValue` member of the `Value` class is a vector that *can* hold `Value` objects, but doesn't construct any when default-initialized, so there is no recursion. The only way to get yourself into trouble here is if you try to add any `Value` objects to the vector *within* the `Value` constructor, including doing so implicitly by resizing the vector. That would be infinite recursion. Otherwise, you're fine.
Tyler McHenry
No, you can't reference Value inside of Value becuase the size isn't known. The best you could do is have a vector<Value*> inside of Value.
miked
You might be right, there miked. I haven't done C++ in a while, as you can probably tell from that I've been doing Java lately. However, I'm confident this basic approach will help solve Ray's problem.
glowcoder
@Tyler, that code is undefined behavior. You are not allowed to instantiate a standard template (including `auto_ptr` but also `vector`) using an incomplete type.
Johannes Schaub - litb
@litb: Where in the standard is that requirement? I have not found any requirement in 23.1 that the type must be complete there. What is undefined behavior is if the vector (or auto\_ptr) destructor is instantiated before the type is complete, which is what inhibits the usage of `auto_ptr` to hold a Pimpl pointer if the class destructor is synthesized. Or am I missing something here?
David Rodríguez - dribeas
@David see 17.5.3.8 [res.on.functions]. I've no access to c++03 currently, so i'm using c++0x draft which allows incomplete types for certain components if explicitly allowed for them. C++03 forbids them for all components.
Johannes Schaub - litb
By comparing the FCD and the current version I have located the same restriction in 17.4.3.6[lib.res.on.functions]/2. Last item in the list.
David Rodríguez - dribeas
A: 

Your Value type could be a (smart) pointer to a base class from which you'd derive classes for integers, strings, dictionnaries, ...

AProgrammer
+1  A: 

I think you need an extra layer of abstraction here.

Your 'variable' should model the binding of some internal object with a 'name' in the language you're building. The 'object' should model the representation.

This way, a variable can hold anything, it's a 'variant'. A certain kind of Object may contain an array of other objects.

A hint:

class Object {
public:
   enum etype { cInt, cString, cArray, cDictionary };
   virtual etype type() const = 0;
   virtual ~Object(){} // don't forget virtual destructor
   // maybe some reference counter functions?...
};

class Variable {
public:
    string name;
    Object* value;
};

class Array : public Object {
   std::map<size_t, Object*> objects_; //or smart pointers...
public:
   virtual etype type() const { return cArray; }
   Object* get( size_t i ) const { return objects_[i]; }
   void put( size_t i, Object* o ) { objects_[i] = o;  }
};

class Int : public Object {
public:
    virtual etype type() const { return cInt; }  
    int value_;
};
xtofl