So I just finished sketching out the scripting system to use for my XNA projects. The problem is non-trivial, since I don’t have the luxury of using the CodeCompiler on the 360 and thus must do a bunch of leg-work myself.

First, the big money question: do I even need a scripting system? The answer is “maybe” but leans more toward “probably not, but it’s an interesting problem I’d like to tackle anyway.” Using Reflection, I could dynamically instantiate some classes that act as my scripts, and I’d get Edit & Continue capabilities, debugging, compile-time checking and dynamic reload, and performance would be a hell of a lot better than any scripting system. In fact, the more I think about it, the more I think today’s work was a wasted effort.

But I’m going to talk about my solution anyway.

Reflection eases a lot of pain for the game-script bridge, since I can get fields and call methods dynamically. This is slow though, and it’s important to (a)cache as much as possible, (b)provide pathways to not go through reflection for more commonly used methods/fields, and (c)avoid using scripts for performance-critical sections. (a) isn’t hard - the first time you encounter a type, cache its FieldInfo and MethodInfo in dictionaries for quicker reference. (b) is a tad trickier, and I don’t yet have a facility for it (because I haven’t needed one), but it might be possible to tag certain methods with helper variants that all have the same signature and can be called manually. In any case, you’re always going to be hit by the performance penalty that comes with boxing/unboxing.

Then there’s the problem of parsing. Which is, when you get right down to it, a huge pain. First you tokenize a script statement (not especially hard). A statement has a few things:
An operation - is this an ‘if’ statement, a ‘for’ statement, or some generic function call/math expression.
A series of expressions - the ‘if’ statement takes a single boolean expression, the ‘for’ takes three expressions, and so on.
Jump points - it’s useful to know where to jump for certain commands. For example, at the end of a for loop, you need to jump back to the beginning; if a for condition is false, you want to jump to the end.

Tokenizing the series of expressions is where things get particularly annoying. First you have to break apart the infix expression, storing each item in a meaningful way that it can be evaluated later. I have an ExpressionItem, where an ExpressionItem can be of type LITERAL, VARIABLE, COLLECTION_VARIABLE, FUNCTION, PAREN, OPERATOR. Some of these ExpressionItems can have sub-ExpressionItems (a COLLECTION_VARIABLE has a sub-expression for its index/key, and a FUNCTION has sub-expressions for its parameters).

Then you really want to convert that infix to postfix, since postfix is considerably easier to evaluate.

When you go to execute the script, you execute statement-by-statement. You’ll need to evaluate those postfix expressions, often going back to the game-script bridge to get the value of variables or call methods. Depending on the results of some of those statements, you may end up jumping, which is fine.

What I have here is very similar to the system I used for my Master’s research, except I’d have to write the parsing myself since I don’t have the luxury of Lex/Yacc. Though annoying, the parsing isn’t *that* hard. When it’s all said and done, I think I can have a full scripting solution in a few hundred lines of code.

Of course, again, now that I think about it, for my games it’s probably not all that critical… Bah.

They’re always cooking.