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:

Contents
 Cleaning Up
 Loading From Text
 Scanning
 Matching
 Basic File Handling
 Loading From File

 Source code
 Printable version
 Discuss this article

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


Loading From Text

We now must decide how we are going to process scripts from a simple text-based format. The format will use a syntax similar to the one illustrated in examples from the previous articles. The only real difference is a lack of commas for additional simplicity.

A single instruction will have syntax of the form:

opcode arg1 arg2 ... argN

Where the opcode and possible arguments are delimited by white space. A script would then be a list of such instructions, with each instruction on a new line:

opcode1 arg1 arg2 ... argN
opcode2 arg1 arg2 ... argN
...and so on

In order to utilize the information present in this text-based format, we will have to construct a simple parser. The first part of this parser will scan a line of text and create a list of tokens. For the sake of simplicity, these tokens will simply be of type char (like our instruction and variable data), so that they can correspond directly to a value.

An interface for the Scanner:

typedef std::vector<char> CharArray;  // an array of char tokens

class Scanner
{
public:
    bool ScanLine(const std::string& line);  // tokenize a line and return success
    const CharArray& GetTokens() const;      // get tokens from most recent scan
};

With this interface in hand, we can now outline our test. After every successful scan, the tokens will be used to create an instruction, which will be placed at the end of a list of instructions. Any failure to scan a line will notify the user and not create an instruction for that particular scan. To complete the entering of a list of instructions, the user inputs "end" and a final op_end instruction will be appended to the list, to ensure a script based off these instructions will not run beyond its own length.

int main()
{
    VirtualMachine vm;
    Scanner scanner;
    vector<Instruction> instrList;

    char buffer[BUFFER_SIZE];
    string input;

    // begin reading text lines from user
    cout << "Input script instructions:" << endl;
    while (input != "end")
    {
        cin.getline(buffer, BUFFER_SIZE);
        input = buffer; // may as well use the string
        if (scanner.ScanLine(input))
        {
            const CharArray& tokens = scanner.GetTokens();
            opcode code = static_cast<opcode>(tokens[0]);
            instrList.push_back(Instruction(code, &tokens[1], tokens.size()-1));
        }
        else
            cout << "Invalid Instruction!" << endl;
    }

    // as a safety precaution, it couldn't hurt to have redundant ends
    instrList.push_back(Instruction(op_end));
    . . .

The user will then be prompted to provide the number of variables the script will need to store in order to run properly. With the instruction list and the variable count, the script will be created, loaded, executed, and have its variable state exposed.

    . . .
    // obtain a variable count
    size_t varCount;
    cout << "Input required variables count: ";
    cin >> varCount;

    Script script(instrList, varCount);

    // load the script and save the id
    size_t scriptID = vm.Load(script);

    // execute script by its id
    cout << endl << "***EXECUTING SCRIPT***" << endl;
    vm.Execute(scriptID);

    // check out the variable states
    cout << endl << "***VARIABLE STATES***" << endl;
    vm.ShowVariableState();

    return 0;
}

This test puts a bit of faith in the user's ability to identify the number of variables required by a particular set of instructions. Without a mechanism for analyzing the tokens scanned for correctness, it will also fail if the user does not provide sufficient data with a particular opcode. As a result, this is definitely not suitable for a final interface for scripting, but will suffice for now to test the scanner. Now we need to complete the scanner's implementation.



Next : Scanning