Skip to main content
GameDev.net gamedev.net
🔒 Locked

Interpreter stack question

Started by ConorJH May 28, 2015 at 10:56 AM 2 replies 2.3k views
Original Post
ConorJH
ConorJH

Im trying to implement a VM/interpreter for a toy language, and have gone the stack based route. Local variables, parameters etc get pushed onto the stack, and popped back off once the function completes and scope is returned to the caller (Illustration below)

_18027_figure351.gif

All of the literature Iv read suggests using a stack, but they will then randomly access elements (say accessing func1's parameters from within func1). Is this achieved by popping everything off the stack until you reach the desired element, use it, then push everything back on in reverese?

Or is the stack not actually something like std::stack and something like a vector or just a contiguous piece of memory the VM/interpreter is managing?

Hodgman
Hodgman
As well as push/pop, you can implement peek(n) which lets you inspect the n'th element without popping it.
You might also want pop(n) which would remove the top n elements.
alh420
alh420

Or is the stack not actually something like std::stack and something like a vector or just a contiguous piece of memory the VM/interpreter is managing?

Implementation-wise, yes, the stack is most probably contiguous memory, so a "peek" should be quick and easy to implement.

Note that also std::stack isn't really a container, it just wraps a container. Default is std::deque, but it could be any class that implement size, empty, back, push_back and pop_back.

For a scripting language, I would try make sure that func1() would use the variables in place, through pointers, as if they are the variables they are, and not caring that they happen to be allocated on a stack.

So the stack shouldn't be implemented like a std::stack (with the type safety, only being possible to push one type), but more like a custom linear allocator.

SmkViper
SmkViper
In a VM there really isn't any need to conform to someone else's implementation of a stack as most of them are going to be very low level (usually cause they're going to be compiled to machine language and need to follow certain calling patterns). For a VM, you just need a stack of frames and you can implement them however is easiest for you.

In my VM a stack is simply a singly-linked list of frame objects (backed by a custom allocator and additional data that allows frames to be split across multiple stack memory pages for speed, but that's not important). The stack simply stores a pointer to the top frame, and each frame stores a pointer to the calling frame. Each frame then also stores an array of all variables needed for a function, including the parameters. Script code compiles into instructions that access those variables by index.

Simplified version (no guarantees on working or even being "good" C++ code):

class Stack
{
public:
  void PushFunction(const FrameData& aFrameData)
  {
    auto newTop = std::make_unique<Frame>(aFrameData); // this is whatever data you need to make a frame
    newTop->SetPrevFrame(std::move(Top));
    Top = std::move(newTop);
  }

  void PopFunction(Variable aFunctionRetVal)
  {
    ReturnRegister = std::move(aFunctionRetVal);
    auto oldTop = std::unique_ptr<Frame>(std::move(Top));
    Top = oldTop->PopPrevFrame();
  }
private:
  Variable ReturnRegister; // for holding the return value from functions
  std::unique_ptr<Frame> Top;
};

class Frame
{
public:
  Frame(const FrameData& aFrameData) { ... }

  void SetPrevFrame(std::unique_ptr<Frame> aFrame)
  {
    PrevFrame = std::move(aFrame);
  }

  std::unique_ptr<Frame> PopPrevFrame()
  {
    auto retVal = std::move(PrevFrame);
    return retVal; // separating move from return to take advantage of RVO
  }

  void SetValue(const unsigned int aIndex, Variable aNewValue)
  {
    Variables[aIndex] = std::move(aNewValue);
  }

  Variable GetValue(const unsigned int aIndex)
  {
    return Variables[aIndex];
  }
private:
  std::vector<Variable> Variables;
  std::unique_ptr<Frame> PrevFrame;
};

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.