Saturday, July 16, 2011

AS3 embedded language virtual machine and compiler beta release

Download my simple, domain specific still-in-beta embedded-in-ActionScript scripting language I am writing for my game! Includes compiler and virtual machine.

I have found that recently some people have been coming to my blog in search of a scripting language that one can embed in ActionScript. I have written a few blog entries about my look into this and my accomplishments but they have been lacking in code and have been nothing more than updates to no one about my own progress. I haven't been updating as often as I'd like and I would really like to show off the actual virtual machine I've created along with the compiler so I have decided since people have been looking for it, I'll bite the bullet and put it up. The scripting language I have written is called CandyScript. It is extremely simple so far and not super powerful, but it does what I need it to do for now. It is also still in "beta" because I am actively working on it; this release isn't really a library, it's just a simple code base people interested can learn from.

The reason why I haven't yet posted anything is because I am also a newbie at creating domain specific languages. I originally thought that I would hold off until I had an actual library but to be honest, library bloat is always annoying and a lot of people don't want some blogger's "library" but just some code they can look at/use/play around with. My scripting language is a secondary project to my game; I am not going to generalize it for everyone's needs and maintain it as such so that it is a true library so why pretend that I will? Instead, I think it is a fairly straight-forward virtual machine and compiler grammar set that I wish I could have looked at when I was figuring out the stuff and that I hope is useful for people who want to see a simple machine in action. It isn't file after file after linked library; if you have an initial grounding in the topic you should be able to step through my implementation in a debugger and read through the code and get an idea of what is happening. Even before then, you can play around and see what I did just by writing scripts and sending them through my VM. There are only two "meaty" classes: an interpreter which loads a compiled script into memory and a virtual machine which executes the script. Seven tiny extra classes provide support to these two main classes (a few are just dummy classes written to represent types such as null). Likewise, the ANTLR grammar is split into two files; one which parses the C-subset scripting language I wrote into an abstract syntax tree and one which turns the tree into a compiled XML file.

I would just like to make one thing clear; I hope I can help people understand better about virtual machines by using and looking at my code. But I am also pretty much a newbie to this field as well. There may be naive mistakes and implementations littering my code; I do not know. All I know is it seems to work for me. It is in beta, however, and I am designing it to my needs, not generalized needs. I can't vouch for it as though I am an expert level DSL writer who knows all the tricks of writing interpreters and compilers; to an expert this may (or may not) look laughably amateurish. All I know, once again, is that it works and seems to work pretty fast for a scripting language literally built on top of another scripting language :) I hope people can learn from this and that someone doesn't come by and telling me I am leading everyone terribly astray; even if I am, my blog certainly doesn't generate enough traffic for me to find that out :)

Here are some details on the release and on the language. First of all, the zip file contains a "Compiler" folder and a "Virtual Machine" folder. The compiler is all ANTLR and Java; it takes my C-subset language and parses it into an XML abstract syntax tree layout of my own design. There is a binary included of this compiler: "csc.jar". There is also a simple shell script, "csc", which pretty much negates the need to call Java when running "csc.jar". Either way, two arguments are passed and the second one is optional. The first argument is the CandyScript file to be compiled (*.csc). The second, optional parameter is -dot. If you included that, instead of outputting a compiled *.xml file, you will instead get a *.dot file which contains the abstract syntax tree in a format viewable in Graphviz. This can help visualize the structure of your compiled XML file and the way a computer would handle you code in any language, really. Also, you might find bugs with it, too if you really try and push the limits and maybe find mistakes I have made that I don't know of :) If you do not already have it, you need "antlr-3.3-complete.jar" which you can find on the ANTLR website or on Google, in order to use the compiler. The JAR file expects it in "/Developer/" but if you aren't on a Mac or want it some place else, you will have to specify the classpath location of "antlr-3.3-complete.jar" when running the program.

The compiler source release includes two ANTLR grammars (one for parsing CandyScript into an AST and one for printing the AST into the proper XML file) and one main compiler class written in Java. If you would like to build from source, you will have to learn about how ANTLR works, however the basic idea is you generate the java files from the ANTLR grammars, compile everything together with my class and then build a jar file if you would like (I have included the necessary materials to build a jar like the one I include).

The virtual machine is all ActionScript. There is not a front end for you to play with, you have to open up Flash and run from there. The candyscript.fla file expects to be edited with a path to the compiled script XML file; this is all you have to change to run a script just to play around. Adding external functionality beyond tracing out to the Flash console involves diving into the code :) I am including a "Hello world" script and you can go from there.

The syntax of the script files is C-like. There are comments such as // and /* */. The scripting language, however, is rooted in functions. The idea is that in a game, map files or other files could have, say, locations that are tied to a function name. The engine, when a player reaches a certain location will see "oh, I need to call this script function". The script function is then called by the virtual machine. Therefore, free floating code in a script will not work or compile. All code must be inside functions. The way I have set up the candyscript.fla file is to automatically execute a main() function. So all your initial code should go in there. However, you can have candyscript.fla call whatever functions you want it to and functions in CandyScript can call other functions. Look at the example script to see what this looks like.

Functions can call other functions. There is support for for and while loops. There is support for if, else if, else blocks. The supported primitives are int, float, bool and String. There is a "standard library" (aka list of functions specially handled by the machine) that supports (so far) various types of timers and also a random number generator. There is one hook built in that prints out results to the Flash console. Look in the Virtual Machine class near the bottom for all of these functions. I would recommend playing around and stepping through the execution to get an understanding of what I am doing, if you are trying to learn how to implement something similar yourself. Updates may come in the future (I am working on this still, I will decide whether my work is worth posting a new version of or not).

No comments:

Post a Comment