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
84 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 File

Using what we have, the simplest way to read in the data from a file written in our format would be to write the entire file into a string and be done with it:

// prompt user to enter a filename
cout << "Enter path/name of script file: ";
cin.getline(buffer, BUFFER_SIZE);

// attempt to open the file
TextReaderFile file(buffer);
if (file.Bad())
{
    cout << "Could not open file!" << endl;
    return 0;
}

// read in file data
string fileData;
fileData.resize(file.Length());
file.Read(fileData, fileData.length());

Sub-strings that represent each line of the file could then be fed into the scanner to build the instruction list:

size_t begin = 0, end = 0, lineNum = 1, varCount = NUM_VARIABLES;
// feed data into scanner and build instructions
while (end != string::npos)
{
    // grab a line from the file data
    end = fileData.find_first_of("\n", begin);
    string line(fileData, begin, end-begin);
    begin = end+1;  // move past '\n' character

    // scan the line
    if (scanner.ScanLine(line))
    {
        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;
        cout << "Line number: " << lineNum << endl;
        cout << "Line: " << line << endl;
    }
    ++lineNum;
}

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

The only thing we lack now is a way to determine the number of variables to reserve for the script. It would probably be best to place this information at the start of the file as a sort of header. Although it doesn't necessarily have to be in this format, here is an example:

Variables: 4
... list of instructions ...

To avoid further complications for now, it is enough to reserve a reasonable number of variables through use of a pre-defined constant, as I have shown:

size_t . . . varCount = NUM_VARIABLES;

Once the NUM_VARIABLES constant is given a value, it should be possible to compile this new code and feed it an example script as a text file. The sample script I have provided looks like this:

talk
print 72 101 108 108 111 32 87 111 114 108 100
set 0 12
set 1 10
dec 0
inc 1
end

You'll notice of course that the final "end" isn't actually needed, as we automatically provide one after scanning. However, as I commented, it's safe to add redundant ends. This script should have output that looks like this:

I am talking.
Hello World

You'll notice that the values provided to "print" in the script are the ASCII codes for the corresponding characters of the string it displays. The variable state output of the script for 0 and 1 respectively should be:

0: 11
1: 11

Exercises for the Reader

There are many possible improvements to be made to what has been given as example so far. A few improvements stand out, and I leave these for the reader to solve (optionally of course). With a little thought, none of these should be too difficult.

  1. Outputting the variable state to a file instead of the console.
  2. Creating an instruction to display a particular variable state.
  3. Scanning in the desired variable count from a script file to allow it to be determined at run-time.
  4. Implementing instructions to allow the system to drive something you've written in the past.

Conclusion

In the next article I intend to cover topics involving a stack machine and program flow, which will then lead into functions. It's possible that I may cover some of the process involved in compiling down to bytecode, depending on how I decide to handle incorporating functions into the current syntax. It may be desirable to stay away from that for now, however, for the sake of brevity.

A few notes about the sample source code:
I renamed the "ScriptState" class to "Execution" (now nested in the VirtualMachine), which sounds more appropriate for the role it will be taking in the future. I've also separated the code for the console loading from that of the file loading. To switch between either mode using the sample source, simply uncomment the #define for the desired mode, and comment out the other.

As always, feel free to express concern, criticism, or ask any questions you may have. The forum discussion is available, or you may email me: glr9940@rit.edu