Loading From FileUsing 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 ReaderThere 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.
ConclusionIn 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:
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
|