AgendaDuring the course of this article I will illustrate a way to implement the following:
Scripted functions will simply allow your scripts to become more modular, while externally called functions will allow your scripting system to interact with an existing code-base. The second method is how we will create a system that can grab an interface of function pointers from something like a game engine, and then be able to operate this system by calling scripts. Improving the StackAs I said at the end of the last article, the tools for expressing the higher-level concept of functions in scripts have already been provided. Although this is true, the ScopeStack can be enhanced to make things easier for us when trying to pass parameters to a new scope without having to hack around the system. One way to do this is to introduce a second parameter to its PushScope() member which will allow the new scope pushed to include variables pushed onto the stack during the previous scope. In ScopeStack "would" be:
This is good, except that it could cause problems later on if we are not careful. The danger is hinted at by the assertion. The problem here is that if the proper number of variables intended to be parameters aren't pushed onto the stack before calling PushScope(), the new scope will actually leak into data that is strictly intended for use by the old scope. Furthermore, when this scope is popped off the stack, the amount of data the scope had leaked into will be lost. So let's fix the inherent problem in the ScopeStack to deal with this issue. We will make use of an additional data member in the ScopeStack to store the next base offset for the stack in the event of a scope being pushed: size_t _nextBase; A few changes to the scope interface's member functions will now determine the starting offset for the next scope to be pushed onto the stack initially, and every time a new scope is pushed. We have succeeded in squashing this possible bug preemptively. Actual ScopeStack code:
With the changes to our stack, we will need to modify the execution's function to expose its stack state. The difference is that the end of the current scope is now found using the next depth, rather than the current one. If there is no next depth, the end of the stack is used. There was also a bug where the value output was not being taken relative to the first depth (index 0), as it should have been. Well, no harm done. Here is the modified function:
To help during debugging, I have also introduced an instruction that will expose the stack state at our whim. It simply calls ExposeStackState() with the std::cout object as the output stream:
|
|