Testing CommandsTo properly test this new implementation, we will need a simple example system to bind with a virtual machine. The system I provide is simply used to illustrate the processes of binding and using. The functionality provided by it will be essentially trivial. The class doesn't even make use of any data members. One command will draw a certain number of asterisks (stars) with a defined spacing between each. The next will compute a factorial (Another factorial test! Yay!) hard-coded. Notice that the number of functions provided to the virtual machine as an interface is enumerated. This is simply one dirty way of ensuring that a proper number of function pointers are passed: class System { public: enum { num_commands = 2 }; // vm interface int DrawStars(const std::vector<int>& argv) { if (argv.size() < 2) return -1; OutputStars(argv[0], argv[1]); return 0; } int CalcFactorial(const std::vector<int>& argv) { if (argv.size() < 1) return -1; return Factorial(argv[0]); } private: void OutputStars(size_t numStars, size_t padding) { std::string padString; size_t i; for (i = 0; i < padding; ++i) padString += ' '; for (i = 0; i < numStars; ++i) std::cout << '*' << padString; std::cout << std::endl; } int Factorial(size_t input) { // initialize int counter = input; int result = 1; // iterative loop while (counter > 1) { result *= counter; --counter; } // output return result; } }; The only changes necessary in the main.cpp to make use of a system is to instantiate one, provide an array of function pointers to its interface, and alter the declaration of the virtual machine: // typedef for simplification typedef Callback<System, int, int>::Func SystemFunc; SystemFunc commandList[System::num_commands] = { &System::DrawStars, &System::CalcFactorial }; System system; VirtualMachine<System> vm(system, commandList, System::num_commands); Two example scripts follow, one to test each of the system commands. Starcommand: // draws 7 stars with a spacing of 2 pusharg_const 7 pusharg_const 2 call_command 0 end Factorialcommand: // computes the factorial of 9 and displays the result (which should be 362880) pusharg_const 9 call_command 1 load output end ConclusionThe most important parts of our run-time system have now been completed. Our virtual machine's capability for binding with other systems is very powerful, and has lots of avenues that can be explored. Inlining of script functions is a topic that I would eventually like to cover, but in a part related to compiler optimizations. It doesn't really make sense to cover it yet, as writing a function to be inline itself in a script is trivial, and we've been doing it all along. The interesting things come when compiling code from a higher-level language. The callback solution introduced in this part of the series could have made use of implementations found in other libraries, such as the popular boost. Such a route was not taken as such generic libraries often take into account everything under the sun, which would have certainly obfuscated the topic being conveyed. Currently, the utilities for binding a virtual machine to an external system are a bit unwieldy, and require a bit of diligence to make sure the system's interface is passed appropriately. Perhaps we can improve upon this a little bit in the future. The next article will probably begin dealing with creating a compiler. To reduce the learning curve of this series, the language to be compiled will probably be very C-like. Further development of the virtual machine itself may be continued at a later time, though the emphasis of the next wave of articles will be primarily on the compilation process. As always, feel free to use the forum discussion, or contact me by email: glr9940@rit.edu
|
|