Parser/Interpreter strategy

Member
Posts: 45
Joined: 2006.11
Post: #1
I'm currently using JavaCC to create a parser for a relatively simple scripting language for a relatively simple 2D game engine (the green engine, as some of you may recall me talking about it from before).

I'm trying to setup a strategy for parsing this language, and I'd like some advice. As far as I know, there are two general ways this is usually done. In one way, the JavaCC parser also acts as the interpreter at the same time. For more complex languages, the JavaCC parser parses the input into a tree (sometimes using JJTree which comes with JavaCC) which is then either "compiled" or interpreted directly from the tree.

Here is a small, non-comprehensive sample of my language:
Code:
behavior ApplyForce {
    // Can be attached to any type of entity
    // entities have location and velocity implicitly
    target: any;
    respondsTo: default; // behavior applied every frame
    
    // initializer list, configures behavior
    // overrides default values for variables below
    // when instantiated.
    // see entity declaration for example of this
    init(forceX, forceY);

    variables {
        float forceX = 0.0; // default values overridden
        float forceY = 0.0; // when instantiated (by init)
    }
    
    // assumes mass of 1.0 I guess
    // "target" is the accumulated state (the result of
    // other behaviors run before this one is passed
    // on to the next through their "targetNext" into
    // this "target")
    script {
        // operator precedence in effect, * before +
        targetNext.xs = (target.xs + forceX * sys.deltaT);
        targetNext.ys = (target.ys + forceY * sys.deltaT);
    }
}

entity ship {
    class {"collidable", "player"}
    variables {
        int curLife = 10;
        int maxLife = 10;
    }
    behaviors {
        ApplyForce(1.0, 0.0); // always apply this force
        DefaultMove();
    }
}
My language is mostly declarative. That is, most of the game scripts are descriptions of objects in the scene, the scene itself, the behaviors that affect objects in the scene, and types of messages that objects can send each other. I can easily construct these directly in the parser without using complex tree traversals.

One part of the language however is imperative (that is, with statements and flow-control, etc.. ). This is mainly the script part of the behavior definitions that tell how the objects move in the scene and interact with other objects. These work essentially like functions with a set of parameters (the current time in seconds, a reference to the entity that the behavior is acting on, which includes its location, speed, etc.., and optionally the message the behavior is responding to).

The imperative portion of the language needs to be "compiled" into some internal representation that can be interpreted later. In addition, this should be a two step process, because there are two things that may not yet be known: the variables of the object it is attached to, and the variables in the message it is responding to. So in one form it stores the names of those variable references, and in another substitutes these (ie through a lookup table) with integer Keys into the object and message variable tables.

So what I was thinking was this: For the declarative part, ie the definitions of the behaviors, entities, messages and their variables, what types of objects they attach to or the behavior lists of entities and their configurations, are all easily constructed directly by the parser. So I'll do that.

For the imperative part I was thinking more of a tree structure with "statements" being the root (and a script simply being a list of statements. However, beyond this I'm not sure how to structure the tree. There are several examples of this out there but they tend to differ by a great deal and I want something simple. It should support parenthesis around expressions, if/else statements (blocks), a while looping construct, and a for looping construct at the minimum. It should also support local variables defined at the beginning of the script (possibly with another "variables {...}" block similar to the one used by entities and behaviors).

What would be the simplest way to implement this minimal c-like sub-language tree that would also allow for some minimal expandability in the future (we plan on adding immutable arrays and a foreach looping construct, for example)?

Thanks for any advice,
-JeroMiya
Quote this message in a reply
Member
Posts: 37
Joined: 2006.08
Post: #2
JeroMiya Wrote:What would be the simplest way to implement this minimal c-like sub-language tree that would also allow for some minimal expandability in the future (we plan on adding immutable arrays and a foreach looping construct, for example)?

Thanks for any advice,
-JeroMiya

Don't.

The simplest way would be to use an existing language that has all of the hard work done. I'm not saying it's impossible, but geez, what a distraction... just use some JVM scripting language.

http://www.robert-tolksdorf.de/vmlanguages.html
Quote this message in a reply
DoG
Moderator
Posts: 869
Joined: 2003.01
Post: #3
Writing a naive interpreter for any scripting langauge is trivial. Writing a fast one isnt Smile

Unless you are willing to spend A LOT of time on it, just try to use one of the existing languages, eg jscript, Lua, etc. Those have decent interpreters, and are relatively easy to embed. Of course syntax might not be what you had in mind, but its likely what you had in mind is crap anyway Wink
Quote this message in a reply
Member
Posts: 204
Joined: 2002.09
Post: #4
To make your own:
flex
bison

I second using an already existing scripting language.
Quote this message in a reply
Member
Posts: 81
Joined: 2007.05
Post: #5
I think Lua is a good solution. Though, I have to admit there are many confusing examples out there. Its very lightweight. Though, the stack push popping can be a little confusing.

I still consider myself a noob to Lua. Given all the nutty documentation I thought this Lua 5 Quick reference guide was really helpful.

http://luaforge.net/docman/?group_id=80

----

static int myscriptcall(lua_State* L) {
/* send the script a number i */
int i = 1;
/* push to send stuff. */
lua_pushinteger( L, i );
/* one value on the stack */
return 1;
}

static int myscriptcall2(lua_State* L) {

/* examine the stack to get stuff */
int a = lua_tointeger(L, -1);
lua_pop(L, 1);

printf("I got %i\n",a);

/*no return items on the stack */
return 0;
}

lua_State* L = lua_open();
luaL_openlibs(L);
lua_register( L, "myscriptcall", myscriptcall );
lua_register( L, "myscriptcall2", myscriptcall2 );
if( luaL_loadstring(L, script_string_from_file) == 0) {
if( lua_pcall(L, 0, 0, 0) != 0 ) {
printf ("lua: fatal error: `%s'\n", lua_tostring (L, -1));
lua_pop(L, 1);
}
}
else {
//error. we need to pop the stack
printf ("lua: fatal error: `%s'\n", lua_tostring (L, -1));
lua_pop(L, 1);
}

----

#!/usr/local/bin/lua

--[[
test lua script
]]

a = myscriptcall()
print(a)

myscriptcall2(42)
Quote this message in a reply
Post Reply