Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
86 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

 The benefit of data
 Another form
 of data

 Manipulating the

 Source code
 Printable version
 Discuss this article

The Series
 An Introduction
 Data Manipulation
 Dynamic Loading
 The Stack and
 Program Flow

Another Form of Data

Data paired with an instruction is all well and good for allowing flexibility on a per-instruction basis. But what about flexibility between instructions? In order to achieve this, we need data that is accessible by all instructions, for reading and possibly writing. This data is therefore reasonably placed at the level of a running script.

The ownership of this data should be dealt with carefully. Unlike an Instruction's data, we would like this new data to be write-able in addition to being readable. If the ownership is carelessly placed at the hands of a script, then issues may arise when trying to enhance the features your system is capable of, such as when implementing some type of pseudo-multi-processing (parallel execution of scripts). This is because any changes to the script data in one "process" will affect any other "processes" running this same script.

For this reason, we would like to abstract a script's executional state. If and when we do implement such a feature, we can safely create executional states for each process being run. This script state will own the variable data we'd like to use, while the script itself will merely store a count describing how much data it needs when executing. The script state should also include some utilities for manipulating this data, otherwise what's the point of having it?

Our class may look something like this:

// a script's executional state
class ScriptState
    // initialization
    void SetDataSize(size_t varCount)   { _varData.resize(varCount); }

    // data access
    void SetVar(size_t i, char val) { _varData[i] = val; }
    char GetVar(size_t i) const     { return _varData[i]; }
    const std::vector<char>& DataArray() const  { return _varData; }
    std::vector<char>   _varData;

For current demonstrative purposes, char variables will be sufficient. Variables can be set or retrieved by index. If you'd like, you can even retrieve the data in a semi-string form. Keep in mind that it isn't necessarily null-terminated, however.

An aside regarding organization:
At the moment, all of our classes are residing at the same namespace level. While this is ok for the limited number of classes we're working with, the organization could be improved somewhat, possibly through nesting. Instruction would make the most sense nested in Script, with Script and ScriptState nested in VirtualMachine. This is something to keep in mind, and I may make this organizational change in the future.

Now, to make use of this in our VirtualMachine class, we will simply add a ScriptState as a data member. At the moment, since we aren't dealing with parallel executions of scripts, we can get away with this. Later, when implementing this parallel script execution, we will have to relocate this member.

For now, to make use of it, we simply initialize its data size at the start of execution:

void VirtualMachine::Execute(size_t scriptId)
    SelectScript(scriptId);  // select our _instrPtr by script ID

    // initialize variable data

    _instr = _instrPtr;      // set our iterator to the beginning
    . . .

A Helpful Tool

Before we go on to make any new instructions to play around with this variable data, we should take care of one minor, yet very crucial thing. As anyone who has ever had to debug his or her code should know, the debugging process can be a real pain. Utilities to aid in debugging can help a great deal, so we should definitely have a utility built to view the data values stored in a ScriptState at any given time.

Something like this should suffice for now:

void ExposeVariableState(const ScriptState& state) const
    std::vector<char>::const_iterator itr;
    int n = 0;  // used to denote indexed position of value
    for (itr = state.DataArray().begin(); itr != state.DataArray().end(); ++itr, ++n)
        std::cout << n << ": ";
        std::cout << static_cast<int>(*itr);   // cast for numeric value
        std::cout << std::endl;

Little things like these can save you a lot of trouble later on when you just can't seem to get a script to work correctly.

Next : Manipulating the data