Scripting Language Tutorial
by Ryanne "saigo" Dolan
ABSTRACT:
In this article, I will describe the creation of a powerful but simple
scripting language in c++. The language is designed to be embedded in
other programs but also can be used for stand-alone batch files, etc.
To understand this tutorial, I recommend that you try a simpler scipting
engine first, and then take some ideas from this. I also have included
a header so that you can use the scripting engine in your own games if you wish.
WHY USE A SCRIPTING LANGUAGE?
Many articles on scripting languages take much time and effort to explain why
they are so useful in games. I assume, however, that if you are reading this,
you probably already realize the benefits of scripting parts of a game.
You may not realize, however, that scripts can be used in many more applications
than just games. For example, I wrote a very simple mathematic-oriented language
for use in a calculator program. I also have used my own languages to power
shortcuts in windows, to wrap a console app into a windows IDE, and to provide
error messages and help to users of software. Obviously, scripts can be used
by more than just the gaming community.
THE LANGUAGE
This language will resemble BASIC in some respects. However, this language is not
like anyother that I've seen in that it does not use arguments or variables.
We can get away with skipping these seemingly necessary elements because we
are going for simplicity.
So how can we make a powerful language without arguments and variables? The
easy solution is with tokens and stacks.
We will call this language "pocketOp" for now. In a pocketOp script, all tokens,
that is, strings separated with whitespace, are treated basically the same.
Take a look at this script:
I'm sure you noticed that you actually can pass arguments to commands,
but really, they are not arguments. They are simply tokens on the same line.
The commmand 'Print', in this example, doesn't get passed the string that follows
it. Rather, it searches its line for strings, and prints them to
the screen. 'TranslateObject' grabs the three numbers after it and moves an
object to that coordinate.
It might seem easy to guess what's going on here, but some of this will act
differently than what you might expect. I'll break it down for you. The first
line will print 'My name is saigo.' as expected. This happens because, as I
have said, the 'Print' command prints all the tokens after it to screen.
Since TranslateObject grabs only the next three tokens and assumes they are
numbers, the tokens after [30] on the second line are extraneous. They compile,
but don't do anything alone (except reside in memory.)
The third line is a little tricky. The output will be 'hello again again'.
This may seem weird at first. Where did the second 'again' come from? Think
about what the Print command does. When the leftmost Print searches for strings
after it, it finds "hello" and " again". The second Print just finds " again".
In pocketOp, all tokens are in a sense commands. A string can be considered a
command that stores text into memory.
So, now we have an abstract idea of how a script should look. But how do we
go about making this happen in c++? Let's first consider our data structure.
DATA STRUCTURE
Because the token is the fundamental unit of a pocketOp script, it follows
that a CToken object should be our starting point. Here is where we must be
a little creative. Because we do not use arguments, a token must somehow know
what other tokens are on its same line. Then, a token needs only to search its
line for usable tokens and react accordingly. Here is how we represent this idea:
class CToken {
CToken* nextToken;
CToken* previousToken;
}
You probably recognize this as a node. When these are strung together,
that is, when one node points to the next, they are called collectively a
linked list.