Scripting Engine Update:

-added simple function support

Limitations:
-void return type only
-no arguments support

Example:
function void myFunc() {<code>}

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@557 4a71c877-e1ca-e34f-864e-861f7616d084
master
Roman C 2006-08-12 10:02:59 +00:00
parent 8adf85a21b
commit 223ea92358
8 changed files with 5118 additions and 4659 deletions

View File

@ -25,7 +25,7 @@ static BOOL enabled_debug_parts[LOG_LAST];
/* This list _must_ match the enum in debug.h! */
static const char *code_part_names[] = {
"all", "main", "sound", "video", "wz", "3d", "texture",
"net", "memory", "error", "never", "last"
"net", "memory", "error", "never", "script", "last"
};
/**********************************************************************

View File

@ -214,6 +214,7 @@ do { \
#define wz__attribute(x)
#endif
/* Must match code_part_names in debug.c */
enum code_part {
LOG_ALL, /* special: sets all to on */
LOG_MAIN,
@ -226,6 +227,7 @@ enum code_part {
LOG_MEMORY,
LOG_ERROR, /* special; on by default */
LOG_NEVER, /* if too verbose for anything but dedicated debugging... */
LOG_SCRIPT,
LOG_LAST /* _must_ be last! */
};

View File

@ -216,6 +216,9 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
// SDWORD arrayIndex, dimensions, arrayElements[VAR_MAX_DIMENSIONS];
SDWORD instructionCount = 0;
UDWORD CurEvent;
BOOL bStop;
ASSERT((PTRVALID(psContext, sizeof(SCRIPT_CONTEXT)),
"interpRunScript: invalid context pointer"));
psProg=psContext->psCode;
@ -236,6 +239,9 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
// Reset the stack in case another script messed up
stackReset();
//reset return stack
retStackReset();
// Turn off tracing initially
interpTrace = FALSE;
@ -276,276 +282,357 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
opcode = (*ip) >> OPCODE_SHIFT;
instructionCount = 0;
// Run the code
while (ip < pCodeEnd)// && opcode != OP_EXIT)
{
if (instructionCount > INTERP_MAXINSTRUCTIONS)
{
ASSERT((FALSE,
"interpRunScript: max instruction count exceeded - infinite loop ?"));
goto exit_with_error;
}
instructionCount += 1;
CurEvent = index;
bStop = FALSE;
TRCPRINTF(("%-6d ", ip - psProg->pCode));
opcode = (*ip) >> OPCODE_SHIFT;
data = (*ip) & OPCODE_DATAMASK;
switch (opcode)
while(!bStop)
{
// Run the code
if (ip < pCodeEnd)// && opcode != OP_EXIT)
{
case OP_PUSH:
// The type of the value is stored in with the opcode
sVal.type = (*ip) & OPCODE_DATAMASK;
// Copy the data as a DWORD
sVal.v.ival = (SDWORD)(*(ip+1));
TRCPRINTF(("PUSH "));
TRCPRINTVAL(&sVal);
TRCPRINTF(("\n"));
if (!stackPush(&sVal))
if (instructionCount > INTERP_MAXINSTRUCTIONS)
{
// Eeerk, out of memory
ASSERT((FALSE, "interpRunScript: out of memory!"));
ASSERT((FALSE,
"interpRunScript: max instruction count exceeded - infinite loop ?"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_PUSHREF:
// The type of the variable is stored in with the opcode
sVal.type = (*ip) & OPCODE_DATAMASK;
// store the pointer
psVar = interpGetVarData(psGlobals, *(ip + 1));
sVal.v.oval = &(psVar->v.ival);
TRCPRINTF(("PUSHREF "));
TRCPRINTVAL(&sVal);
TRCPRINTF(("\n"));
if (!stackPush(&sVal))
{
// Eeerk, out of memory
ASSERT((FALSE, "interpRunScript: out of memory!"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_POP:
TRCPRINTF(("POP\n"));
if (!stackPop(&sVal))
{
ASSERT((FALSE, "interpRunScript: could not do stack pop"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_BINARYOP:
TRCPRINTMATHSOP(data);
if (!stackBinaryOp((OPCODE)data))
{
ASSERT((FALSE, "interpRunScript: could not do binary op"));
goto exit_with_error;
}
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
ip += aOpSize[opcode];
break;
case OP_UNARYOP:
TRCPRINTMATHSOP(data);
if (!stackUnaryOp((OPCODE)data))
{
ASSERT((FALSE, "interpRunScript: could not do unary op"));
goto exit_with_error;
}
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
ip += aOpSize[opcode];
break;
case OP_PUSHGLOBAL:
TRCPRINTF(("PUSHGLOBAL %d\n", data));
if (data >= numGlobals)
{
ASSERT((FALSE, "interpRunScript: variable index out of range"));
goto exit_with_error;
}
if (!stackPush(interpGetVarData(psGlobals, data)))
{
ASSERT((FALSE, "interpRunScript: could not do stack push"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_POPGLOBAL:
TRCPRINTF(("POPGLOBAL %d ", data));
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
if (data >= numGlobals)
{
ASSERT((FALSE, "interpRunScript: variable index out of range"));
goto exit_with_error;
}
if (!stackPopType(interpGetVarData(psGlobals, data)))
{
ASSERT((FALSE, "interpRunScript: could not do stack pop"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_PUSHARRAYGLOBAL:
// get the number of array elements
// arrayElements = (data & ARRAY_ELEMENT_MASK) >> ARRAY_ELEMENT_SHIFT;
// data = data & ARRAY_INDEX_MASK;
// get the array index
// if (!stackPopParams(1, VAL_INT, &arrayIndex))
// {
// goto exit_with_error;
// }
// TRCPRINTF(("PUSHARRAYGLOBAL [%d] %d(+%d)\n", arrayIndex, data, arrayElements));
// if (data + arrayElements > numGlobals)
// {
// ASSERT((FALSE, "interpRunScript: variable index out of range"));
// goto exit_with_error;
// }
// if (arrayIndex < 0 || arrayIndex >= arrayElements)
// {
// ASSERT((FALSE, "interpRunScript: array index out of range"));
// goto exit_with_error;
// }
TRCPRINTF(("PUSHARRAYGLOBAL "));
if (!interpGetArrayVarData(&ip, psGlobals, psProg, &psVar))
{
ASSERT((FALSE, "interpRunScript: could not get array var data"));
goto exit_with_error;
}
TRCPRINTF(("\n"));
if (!stackPush(psVar))
{
ASSERT((FALSE, "interpRunScript: could not do stack push"));
goto exit_with_error;
}
break;
case OP_POPARRAYGLOBAL:
// get the number of array elements
// arrayElements = (data & ARRAY_ELEMENT_MASK) >> ARRAY_ELEMENT_SHIFT;
// data = data & ARRAY_INDEX_MASK;
// get the array index
/* if (!stackPopParams(1, VAL_INT, &arrayIndex))
{
ASSERT((FALSE, "interpRunScript: could not do pop of params"));
goto exit_with_error;
}
TRCPRINTF(("POPARRAYGLOBAL [%d] %d(+%d) ", arrayIndex, data, arrayElements));
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
if (data + arrayElements > numGlobals)
{
ASSERT((FALSE, "interpRunScript: variable index out of range"));
goto exit_with_error;
}
if (arrayIndex < 0 || arrayIndex >= arrayElements)
{
ASSERT((FALSE, "interpRunScript: array index out of range"));
goto exit_with_error;
}
if (!stackPopType(interpGetVarData(psGlobals, data + arrayIndex)))
{
ASSERT((FALSE, "interpRunScript: could not do pop stack of type"));
goto exit_with_error;
}
ip += aOpSize[opcode];*/
TRCPRINTF(("POPARRAYGLOBAL "));
if (!interpGetArrayVarData(&ip, psGlobals, psProg, &psVar))
{
ASSERT((FALSE, "interpRunScript: could not get array var data"));
goto exit_with_error;
}
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
if (!stackPopType(psVar))
{
ASSERT((FALSE, "interpRunScript: could not do pop stack of type"));
goto exit_with_error;
}
break;
case OP_JUMPFALSE:
TRCPRINTF(("JUMPFALSE %d (%d)",
(SWORD)data, ip - psProg->pCode + (SWORD)data));
if (!stackPop(&sVal))
{
ASSERT((FALSE, "interpRunScript: could not do pop of stack"));
goto exit_with_error;
}
if (!sVal.v.bval)
instructionCount += 1;
TRCPRINTF(("%-6d ", ip - psProg->pCode));
opcode = (*ip) >> OPCODE_SHIFT;
data = (*ip) & OPCODE_DATAMASK;
switch (opcode)
{
/* Custom function call */
case OP_FUNC:
debug( LOG_SCRIPT, "OP_FUNC" );
if(!RetStackRemember(CurEvent, (UDWORD)(ip + 2))) //Remember where to jump back later
{
debug( LOG_ERROR, "interpRunScript() - RetStackRemember() failed.");
return FALSE;
}
CurEvent = *(ip+1); //Current event = event to jump to
if (CurEvent > psProg->numEvents)
{
debug( LOG_ERROR, "interpRunScript: trigger index out of range");
return FALSE;
}
//Set new code execution boundries
//----------------------------------
pCodeBase = psProg->pCode + psProg->pEventTab[CurEvent];
pCodeStart = pCodeBase;
pCodeEnd = psProg->pCode + psProg->pEventTab[CurEvent+1];
ip = pCodeStart; //Start at the beginning of the new event
break;
case OP_PUSH:
// The type of the value is stored in with the opcode
sVal.type = (*ip) & OPCODE_DATAMASK;
// Copy the data as a DWORD
sVal.v.ival = (SDWORD)(*(ip+1));
TRCPRINTF(("PUSH "));
TRCPRINTVAL(&sVal);
TRCPRINTF(("\n"));
if (!stackPush(&sVal))
{
// Eeerk, out of memory
ASSERT((FALSE, "interpRunScript: out of memory!"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_PUSHREF:
// The type of the variable is stored in with the opcode
sVal.type = (*ip) & OPCODE_DATAMASK;
// store the pointer
psVar = interpGetVarData(psGlobals, *(ip + 1));
sVal.v.oval = &(psVar->v.ival);
TRCPRINTF(("PUSHREF "));
TRCPRINTVAL(&sVal);
TRCPRINTF(("\n"));
if (!stackPush(&sVal))
{
// Eeerk, out of memory
ASSERT((FALSE, "interpRunScript: out of memory!"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_POP:
TRCPRINTF(("POP\n"));
if (!stackPop(&sVal))
{
ASSERT((FALSE, "interpRunScript: could not do stack pop"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_BINARYOP:
TRCPRINTMATHSOP(data);
if (!stackBinaryOp((OPCODE)data))
{
ASSERT((FALSE, "interpRunScript: could not do binary op"));
goto exit_with_error;
}
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
ip += aOpSize[opcode];
break;
case OP_UNARYOP:
TRCPRINTMATHSOP(data);
if (!stackUnaryOp((OPCODE)data))
{
ASSERT((FALSE, "interpRunScript: could not do unary op"));
goto exit_with_error;
}
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
ip += aOpSize[opcode];
break;
case OP_PUSHGLOBAL:
TRCPRINTF(("PUSHGLOBAL %d\n", data));
if (data >= numGlobals)
{
ASSERT((FALSE, "interpRunScript: variable index out of range"));
goto exit_with_error;
}
if (!stackPush(interpGetVarData(psGlobals, data)))
{
ASSERT((FALSE, "interpRunScript: could not do stack push"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_POPGLOBAL:
TRCPRINTF(("POPGLOBAL %d ", data));
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
if (data >= numGlobals)
{
ASSERT((FALSE, "interpRunScript: variable index out of range"));
goto exit_with_error;
}
if (!stackPopType(interpGetVarData(psGlobals, data)))
{
ASSERT((FALSE, "interpRunScript: could not do stack pop"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_PUSHARRAYGLOBAL:
// get the number of array elements
// arrayElements = (data & ARRAY_ELEMENT_MASK) >> ARRAY_ELEMENT_SHIFT;
// data = data & ARRAY_INDEX_MASK;
// get the array index
// if (!stackPopParams(1, VAL_INT, &arrayIndex))
// {
// goto exit_with_error;
// }
// TRCPRINTF(("PUSHARRAYGLOBAL [%d] %d(+%d)\n", arrayIndex, data, arrayElements));
// if (data + arrayElements > numGlobals)
// {
// ASSERT((FALSE, "interpRunScript: variable index out of range"));
// goto exit_with_error;
// }
// if (arrayIndex < 0 || arrayIndex >= arrayElements)
// {
// ASSERT((FALSE, "interpRunScript: array index out of range"));
// goto exit_with_error;
// }
TRCPRINTF(("PUSHARRAYGLOBAL "));
if (!interpGetArrayVarData(&ip, psGlobals, psProg, &psVar))
{
ASSERT((FALSE, "interpRunScript: could not get array var data"));
goto exit_with_error;
}
TRCPRINTF(("\n"));
if (!stackPush(psVar))
{
ASSERT((FALSE, "interpRunScript: could not do stack push"));
goto exit_with_error;
}
break;
case OP_POPARRAYGLOBAL:
// get the number of array elements
// arrayElements = (data & ARRAY_ELEMENT_MASK) >> ARRAY_ELEMENT_SHIFT;
// data = data & ARRAY_INDEX_MASK;
// get the array index
/* if (!stackPopParams(1, VAL_INT, &arrayIndex))
{
ASSERT((FALSE, "interpRunScript: could not do pop of params"));
goto exit_with_error;
}
TRCPRINTF(("POPARRAYGLOBAL [%d] %d(+%d) ", arrayIndex, data, arrayElements));
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
if (data + arrayElements > numGlobals)
{
ASSERT((FALSE, "interpRunScript: variable index out of range"));
goto exit_with_error;
}
if (arrayIndex < 0 || arrayIndex >= arrayElements)
{
ASSERT((FALSE, "interpRunScript: array index out of range"));
goto exit_with_error;
}
if (!stackPopType(interpGetVarData(psGlobals, data + arrayIndex)))
{
ASSERT((FALSE, "interpRunScript: could not do pop stack of type"));
goto exit_with_error;
}
ip += aOpSize[opcode];*/
TRCPRINTF(("POPARRAYGLOBAL "));
if (!interpGetArrayVarData(&ip, psGlobals, psProg, &psVar))
{
ASSERT((FALSE, "interpRunScript: could not get array var data"));
goto exit_with_error;
}
TRCPRINTSTACKTOP();
TRCPRINTF(("\n"));
if (!stackPopType(psVar))
{
ASSERT((FALSE, "interpRunScript: could not do pop stack of type"));
goto exit_with_error;
}
break;
case OP_JUMPFALSE:
TRCPRINTF(("JUMPFALSE %d (%d)",
(SWORD)data, ip - psProg->pCode + (SWORD)data));
if (!stackPop(&sVal))
{
ASSERT((FALSE, "interpRunScript: could not do pop of stack"));
goto exit_with_error;
}
if (!sVal.v.bval)
{
// Do the jump
TRCPRINTF((" - done -\n"));
ip += (SWORD)data;
if (ip < pCodeStart || ip > pCodeEnd)
{
ASSERT((FALSE, "interpRunScript: jump out of range"));
goto exit_with_error;
}
}
else
{
TRCPRINTF(("\n"));
ip += aOpSize[opcode];
}
break;
case OP_JUMP:
TRCPRINTF(("JUMP %d (%d)\n",
(SWORD)data, ip - psProg->pCode + (SWORD)data));
// Do the jump
TRCPRINTF((" - done -\n"));
ip += (SWORD)data;
if (ip < pCodeStart || ip > pCodeEnd)
{
ASSERT((FALSE, "interpRunScript: jump out of range"));
goto exit_with_error;
}
break;
case OP_CALL:
TRCPRINTF(("CALL "));
TRCPRINTFUNC( (SCRIPT_FUNC)(*(ip+1)) );
TRCPRINTF(("\n"));
scriptFunc = (SCRIPT_FUNC)*(ip+1);
if (!scriptFunc())
{
ASSERT((FALSE, "interpRunScript: could not do func"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_VARCALL:
TRCPRINTF(("VARCALL "));
TRCPRINTVARFUNC( (SCRIPT_VARFUNC)(*(ip+1)), data );
TRCPRINTF(("(%d)\n", data));
scriptVarFunc = (SCRIPT_VARFUNC)*(ip+1);
if (!scriptVarFunc(data))
{
ASSERT((FALSE, "interpRunScript: could not do var func"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_EXIT:
// jump out of the code
ip = pCodeEnd;
break;
case OP_PAUSE:
TRCPRINTF(("PAUSE %d\n", data));
ASSERT((stackEmpty(),
"interpRunScript: OP_PAUSE without empty stack"));
ip += aOpSize[opcode];
// tell the event system to reschedule this event
if (!eventAddPauseTrigger(psContext, index, ip - pCodeBase, data))
{
ASSERT((FALSE, "interpRunScript: could not add pause trigger"));
goto exit_with_error;
}
// now jump out of the event
ip = pCodeEnd;
break;
default:
ASSERT((FALSE, "interpRunScript: unknown opcode"));
goto exit_with_error;
break;
}
}
else //End of the event reached, see if we have to jump back to the caller function or just exit
{
//reset local vars
//if(!resetLocalVars(psProg, CurEvent))
// goto exit_with_error;
if(!IsRetStackEmpty()) //There was a caller function before this one
{
if(!PopRetStack(&ip)) //Pop return address
{
debug( LOG_ERROR, "interpRunScript() - PopRetStack(): failed to pop return adress.");
return FALSE;
}
if(!PopRetStack(&CurEvent)) //Pop event index
{
debug( LOG_ERROR, "interpRunScript() - PopRetStack(): failed to pop return event index.");
return FALSE;
}
debug( LOG_SCRIPT, "RETURN" );
//Set new boundries
//--------------------------
pCodeBase = psProg->pCode + psProg->pEventTab[CurEvent];
if(CurEvent == index) //If it's the original event, then also use the offset passed
{pCodeStart = pCodeBase + offset;}
else
{pCodeStart = pCodeBase;}
pCodeEnd = psProg->pCode + psProg->pEventTab[CurEvent+1];
}
else
{
TRCPRINTF(("\n"));
ip += aOpSize[opcode];
//reset local vars
//if(!resetLocalVars(psProg, index))
// goto exit_with_error;
bStop = TRUE; //Stop execution of this event here, no more calling functions stored
}
break;
case OP_JUMP:
TRCPRINTF(("JUMP %d (%d)\n",
(SWORD)data, ip - psProg->pCode + (SWORD)data));
// Do the jump
ip += (SWORD)data;
if (ip < pCodeStart || ip > pCodeEnd)
{
ASSERT((FALSE, "interpRunScript: jump out of range"));
goto exit_with_error;
}
break;
case OP_CALL:
TRCPRINTF(("CALL "));
TRCPRINTFUNC( (SCRIPT_FUNC)(*(ip+1)) );
TRCPRINTF(("\n"));
scriptFunc = (SCRIPT_FUNC)*(ip+1);
if (!scriptFunc())
{
ASSERT((FALSE, "interpRunScript: could not do func"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_VARCALL:
TRCPRINTF(("VARCALL "));
TRCPRINTVARFUNC( (SCRIPT_VARFUNC)(*(ip+1)), data );
TRCPRINTF(("(%d)\n", data));
scriptVarFunc = (SCRIPT_VARFUNC)*(ip+1);
if (!scriptVarFunc(data))
{
ASSERT((FALSE, "interpRunScript: could not do var func"));
goto exit_with_error;
}
ip += aOpSize[opcode];
break;
case OP_EXIT:
// jump out of the code
ip = pCodeEnd;
break;
case OP_PAUSE:
TRCPRINTF(("PAUSE %d\n", data));
ASSERT((stackEmpty(),
"interpRunScript: OP_PAUSE without empty stack"));
ip += aOpSize[opcode];
// tell the event system to reschedule this event
if (!eventAddPauseTrigger(psContext, index, ip - pCodeBase, data))
{
ASSERT((FALSE, "interpRunScript: could not add pause trigger"));
goto exit_with_error;
}
// now jump out of the event
ip = pCodeEnd;
break;
default:
ASSERT((FALSE, "interpRunScript: unknown opcode"));
goto exit_with_error;
break;
}
}
TRCPRINTF(("%-6d EXIT\n", ip - psProg->pCode));
bInterpRunning = FALSE;
@ -639,3 +726,60 @@ BOOL interpTraceOff(void)
return TRUE;
}
/* Call stack stuff */
static UDWORD retStack[200]; //Primitive stack
static SDWORD retStackPos; //Current Position, always points to the last valid element
void retStackReset(void)
{
retStackPos = -1; //Beginning of the stack
}
//Remember current script execution adress
UDWORD RetStackRemember(UDWORD EvTrigIndex, UDWORD address)
{
//DbgMsg("To remember: %d, %d, %d", EvTrigIndex, address, retStackPos);
if (retStackPos >= 200)
{
debug( LOG_ERROR, "RetStackRemember() - return address stack is full");
return FALSE; //Stack full
}
retStackPos = retStackPos + 2;
retStack[retStackPos - 1] = EvTrigIndex; //First store event index
retStack[retStackPos] = address; //current ip
return TRUE;
}
BOOL IsRetStackEmpty()
{
if(retStackPos == (-1)) return TRUE;
return FALSE;
}
BOOL PopRetStack(UDWORD *psVal)
{
//DbgMsg("Popping: %d", retStackPos);
if(retStackPos < 0)
{
return FALSE;
}
*psVal = retStack[retStackPos];
retStackPos = retStackPos - 1;
//DbgMsg("Popped: %d, %d", retStackPos, *psVal);
return TRUE;
}
SDWORD GetCallDepth()
{
return (retStackPos + 1) / 2;
}

View File

@ -103,6 +103,8 @@ typedef enum _op_code
OP_LESSEQUAL,
OP_GREATER,
OP_LESS,
OP_FUNC, //custom (in-script) function call
} OPCODE;
/* How far the opcode is shifted up a UDWORD to allow other data to be

View File

@ -213,6 +213,15 @@ typedef struct _event_symbol
UDWORD debugEntries;
SCRIPT_DEBUG *psDebug;
//functions stuff
UDWORD numParams; //Number of parameters to the function
UDWORD numLocalVars; //local variables
BOOL bFunction; //if this event is defined as a function
BOOL bDeclared; //if function was declared before
INTERP_TYPE retType; //return type if a function
INTERP_TYPE aParams[INST_MAXPARAMS];
struct _event_symbol *psNext;
} EVENT_SYMBOL;
@ -258,7 +267,7 @@ extern BOOL scriptAddVariable(VAR_DECL *psStorage, VAR_IDENT_DECL *psVarIdent);
extern BOOL scriptAddTrigger(STRING *pIdent, TRIGGER_DECL *psDecl, UDWORD line);
/* Add a new event symbol */
extern BOOL scriptDeclareEvent(STRING *pIdent, EVENT_SYMBOL **ppsEvent);
extern BOOL scriptDeclareEvent(STRING *pIdent, EVENT_SYMBOL **ppsEvent, INT numArgs);
// Add the code to a defined event
extern BOOL scriptDefineEvent(EVENT_SYMBOL *psEvent, CODE_BLOCK *psCode, SDWORD trigger);

View File

@ -55,6 +55,18 @@ extern void scriptSetCallbackTab(CALLBACK_SYMBOL *psCallTab);
/* Set the type equivalence table */
extern void scriptSetTypeEquiv(TYPE_EQUIV *psTypeTab);
/***********************************************************************************
*
* Return stack stuff
*/
extern void retStackReset(void);
extern UDWORD RetStackRemember(UDWORD EvTrigIndex, UDWORD address);
extern BOOL IsRetStackEmpty();
extern BOOL PopRetStack(UDWORD *psVal);
extern SDWORD GetCallDepth();
/***********************************************************************************
*
* Compiler functions

View File

@ -1,384 +1,446 @@
%{
/*
* script.l
*
* Script file lexer.
*/
#include "lib/framework/frame.h"
#include "interp.h"
#include "parse.h"
#include "script.h"
/* Get the Yacc definitions */
#include "script_parser.h"
/* Maximum length for any TEXT value */
#ifndef YYLMAX
#define YYLMAX 255
#endif
/* Store for any string values */
static STRING aText[TEXT_BUFFERS][YYLMAX];
static UDWORD currText=0;
// Note if we are in a comment
static BOOL inComment = FALSE;
/* Pointer to the input buffer */
static UBYTE *pInputBuffer = NULL;
static UBYTE *pEndBuffer = NULL;
#define YY_INPUT(buf, result, max_size) \
if (pInputBuffer != pEndBuffer) { \
buf[0] = *(pInputBuffer++); result = 1; \
} else { \
buf[0] = EOF; result = YY_NULL; \
}
#undef scr_getc
#define scr_getc() (pInputBuffer != pEndBuffer ? *(pInputBuffer++) : EOF)
/* Get the token type for a variable symbol */
SDWORD scriptGetVarToken(VAR_SYMBOL *psVar)
{
BOOL object;
// See if this is an object pointer
if (!asScrTypeTab || psVar->type < VAL_USERTYPESTART)
{
object = FALSE;
}
else
{
object = asScrTypeTab[psVar->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
}
if (psVar->storage == ST_OBJECT)
{
/* This is an object member variable */
if (object)
{
return OBJ_OBJVAR;
}
else
{
switch (psVar->type)
{
case VAL_BOOL:
return BOOL_OBJVAR;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_OBJVAR;
break;
default:
return USER_OBJVAR;
break;
}
}
}
else if (psVar->dimensions > 0)
{
/* This is an array variable */
if (object)
{
return OBJ_ARRAY;
}
else
{
switch (psVar->type)
{
case VAL_BOOL:
return BOOL_ARRAY;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_ARRAY;
break;
default:
return VAR_ARRAY;
break;
}
}
}
else
{
/* This is a standard variable */
if (object)
{
return OBJ_VAR;
}
else
{
switch (psVar->type)
{
case VAL_BOOL:
return BOOL_VAR;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_VAR;
break;
default:
return VAR;
break;
}
}
}
}
/* Get the token type for a constant symbol */
SDWORD scriptGetConstToken(CONST_SYMBOL *psConst)
{
BOOL object;
// See if this is an object constant
if (!asScrTypeTab || psConst->type < VAL_USERTYPESTART)
{
object = FALSE;
}
else
{
object = asScrTypeTab[psConst->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
}
switch (psConst->type)
{
case VAL_BOOL:
return BOOL_CONSTANT;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_CONSTANT;
break;
default:
if (object)
{
return OBJ_CONSTANT;
}
else
{
return USER_CONSTANT;
}
break;
}
}
/* Get the token type for a function symbol */
SDWORD scriptGetFuncToken(FUNC_SYMBOL *psFunc)
{
BOOL object;
// See if this is an object pointer
if (!asScrTypeTab || psFunc->type < VAL_USERTYPESTART)
{
object = FALSE;
}
else
{
object = asScrTypeTab[psFunc->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
}
if (object)
{
return OBJ_FUNC;
}
else
{
switch (psFunc->type)
{
case VAL_BOOL:
return BOOL_FUNC;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_FUNC;
break;
case VAL_VOID:
return FUNC;
break;
default:
return USER_FUNC;
break;
}
}
}
%}
%option prefix="scr_"
%option nounput
%option yylineno
%x COMMENT
%x SLCOMMENT
%x QUOTE
%%
/* Match to key words */
/*begin return START;*/
/*end return END;*/
wait return WAIT;
every return EVERY;
trigger return TRIGGER;
event return EVENT;
inactive return INACTIVE;
init return INITIALISE;
link return LINK;
ref return REF;
/* function return FUNCTION;*/
/* cond return COND; */
public { scr_lval.stype = ST_PUBLIC; return STORAGE; }
private { scr_lval.stype = ST_PRIVATE; return STORAGE; }
while return WHILE;
if return IF;
else return ELSE;
exit return EXIT;
pause return PAUSE;
/* Match to type key words */
bool { scr_lval.tval = VAL_BOOL; return TYPE; }
BOOL { scr_lval.tval = VAL_BOOL; return TYPE; }
int { scr_lval.tval = VAL_INT; return TYPE; }
INT { scr_lval.tval = VAL_INT; return TYPE; }
/*float { ais_lval.tval = VAL_FLOAT; return TYPE; }*/
/* string type isn't implemented yet */
/* string { ais_lval.tval = VAL_STRING; return TYPE; } */
/* object { scr_lval.tval = VAL_OBJECT; return TYPE; } */
/* Match boolean values */
TRUE { scr_lval.bval = TRUE; return BOOLEAN_T; }
true { scr_lval.bval = TRUE; return BOOLEAN_T; }
FALSE { scr_lval.bval = FALSE; return BOOLEAN_T; }
false { scr_lval.bval = FALSE; return BOOLEAN_T; }
/* Match boolean operators */
"==" return BOOLEQUAL;
"!=" return NOTEQUAL;
">=" return GREATEQUAL;
"<=" return LESSEQUAL;
">" return GREATER;
"<" return LESS;
and return _AND;
AND return _AND;
or return _OR;
OR return _OR;
not return _NOT;
NOT return _NOT;
/* Match floating point numbers */
/*-?[0-9]*"."[0-9]+ { scr_lval.fval = (float)atof(scr_text); return FLOAT; }*/
/* Match integer numbers */
-?[0-9]+ { scr_lval.ival = atol(scr_text); return INTEGER; }
/* Match identifiers */
[a-zA-Z][0-9_a-zA-Z]* {
/* See if this identifier has been defined as a type */
if (scriptLookUpType(scr_text, &scr_lval.tval))
{
DBP0(("[lex] TYPE\n"));
return TYPE;
}
/* See if this identifier has been defined as a variable */
else if (scriptLookUpVariable(scr_text, &scr_lval.vSymbol))
{
DBP0(("[lex] variable\n"));
return scriptGetVarToken(scr_lval.vSymbol);
}
/* See if this identifier has been defined as a constant */
else if (scriptLookUpConstant(scr_text, &scr_lval.cSymbol))
{
DBP0(("[lex] constant\n"));
return scriptGetConstToken(scr_lval.cSymbol);
}
/* See if this identifier has been defined as a function */
else if (scriptLookUpFunction(scr_text, &scr_lval.fSymbol))
{
DBP0(("[lex] func\n"));
return scriptGetFuncToken(scr_lval.fSymbol);
}
else if (scriptLookUpTrigger(scr_text, &scr_lval.tSymbol))
{
DBP0(("[lex] TRIG_SYM\n"));
return TRIG_SYM;
}
else if (scriptLookUpEvent(scr_text, &scr_lval.eSymbol))
{
DBP0(("[lex] EVENT_SYM\n"));
return EVENT_SYM;
}
else if (scriptLookUpCallback(scr_text, &scr_lval.cbSymbol))
{
DBP0(("[lex] CALLBACK_SYM\n"));
return CALLBACK_SYM;
}
else
{
strcpy(aText[currText], scr_text);
scr_lval.sval = aText[currText];
currText = (currText + 1) % TEXT_BUFFERS;
DBP0(("[lex] IDENT\n"));
return IDENT;
}
}
/* Match quoted text */
\" { BEGIN QUOTE; }
<QUOTE>\" { BEGIN 0; }
<QUOTE>[^\"\n]* {
strcpy(aText[currText], scr_text);
scr_lval.sval = aText[currText];
currText = (currText + 1) % TEXT_BUFFERS;
return QTEXT;
}
/* Skip white space */
[ \t\n\x0d\x0a] ;
/* Strip comments */
"/*" { inComment=TRUE; BEGIN COMMENT; }
<COMMENT>"*/" |
<COMMENT>"*/"\n { inComment=FALSE; BEGIN 0; }
<COMMENT>. |
<COMMENT>\n ;
/* Strip single line comments */
"//" { BEGIN SLCOMMENT; }
<SLCOMMENT>\n { BEGIN 0; }
<SLCOMMENT>[^\n]* ;
/* Match anything that's been missed and pass it as a char */
. return scr_text[0];
%%
/* Set the current input buffer for the lexer */
void scriptSetInputBuffer(UBYTE *pBuffer, UDWORD size)
{
pInputBuffer = pBuffer;
pEndBuffer = pBuffer + size;
/* Reset the lexer in case it's been used before */
scr__flush_buffer( YY_CURRENT_BUFFER );
}
void scriptGetErrorData(int *pLine, char **ppText)
{
*pLine = scr_lineno;
*ppText = scr_text;
}
int scr_wrap(void)
{
if (inComment)
{
DBERROR(("Warning: reched end of file in a comment"));
}
return 1;
}
%{
/*
* script.l
*
* Script file lexer.
*/
#include "lib/framework/frame.h"
#include "interp.h"
#include "parse.h"
#include "script.h"
/* Get the Yacc definitions */
#include "script_parser.h"
/* Maximum length for any TEXT value */
#ifndef YYLMAX
#define YYLMAX 255
#endif
/* Store for any string values */
static STRING aText[TEXT_BUFFERS][YYLMAX];
static UDWORD currText=0;
// Note if we are in a comment
static BOOL inComment = FALSE;
/* Pointer to the input buffer */
static UBYTE *pInputBuffer = NULL;
static UBYTE *pEndBuffer = NULL;
#define YY_INPUT(buf, result, max_size) \
if (pInputBuffer != pEndBuffer) { \
buf[0] = *(pInputBuffer++); result = 1; \
} else { \
buf[0] = EOF; result = YY_NULL; \
}
#undef scr_getc
#define scr_getc() (pInputBuffer != pEndBuffer ? *(pInputBuffer++) : EOF)
/* Get the token type for a variable symbol */
SDWORD scriptGetVarToken(VAR_SYMBOL *psVar)
{
BOOL object;
// See if this is an object pointer
if (!asScrTypeTab || psVar->type < VAL_USERTYPESTART)
{
object = FALSE;
}
else
{
object = asScrTypeTab[psVar->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
}
if (psVar->storage == ST_OBJECT)
{
/* This is an object member variable */
if (object)
{
return OBJ_OBJVAR;
}
else
{
switch (psVar->type)
{
case VAL_BOOL:
return BOOL_OBJVAR;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_OBJVAR;
break;
default:
return USER_OBJVAR;
break;
}
}
}
else if (psVar->dimensions > 0)
{
/* This is an array variable */
if (object)
{
return OBJ_ARRAY;
}
else
{
switch (psVar->type)
{
case VAL_BOOL:
return BOOL_ARRAY;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_ARRAY;
break;
default:
return VAR_ARRAY;
break;
}
}
}
else
{
/* This is a standard variable */
if (object)
{
return OBJ_VAR;
}
else
{
switch (psVar->type)
{
case VAL_BOOL:
return BOOL_VAR;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_VAR;
break;
default:
return VAR;
break;
}
}
}
}
/* Get the token type for a constant symbol */
SDWORD scriptGetConstToken(CONST_SYMBOL *psConst)
{
BOOL object;
// See if this is an object constant
if (!asScrTypeTab || psConst->type < VAL_USERTYPESTART)
{
object = FALSE;
}
else
{
object = asScrTypeTab[psConst->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
}
switch (psConst->type)
{
case VAL_BOOL:
return BOOL_CONSTANT;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_CONSTANT;
break;
default:
if (object)
{
return OBJ_CONSTANT;
}
else
{
return USER_CONSTANT;
}
break;
}
}
/* Get the token type for a function symbol */
SDWORD scriptGetFuncToken(FUNC_SYMBOL *psFunc)
{
BOOL object;
// See if this is an object pointer
if (!asScrTypeTab || psFunc->type < VAL_USERTYPESTART)
{
object = FALSE;
}
else
{
object = asScrTypeTab[psFunc->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
}
if (object)
{
return OBJ_FUNC;
}
else
{
switch (psFunc->type)
{
case VAL_BOOL:
return BOOL_FUNC;
break;
case VAL_INT:
// case VAL_FLOAT:
return NUM_FUNC;
break;
case VAL_VOID:
return FUNC;
break;
default:
return USER_FUNC;
break;
}
}
}
/* Get the token type for a custom function symbol */
SDWORD scriptGetCustomFuncToken(EVENT_SYMBOL *psFunc)
{
BOOL object;
debug( LOG_SCRIPT, "scriptGetCustomFuncToken" );
// See if this is an object pointer
object = asScrTypeTab[psFunc->retType - VAL_USERTYPESTART].accessType == AT_OBJECT;
debug( LOG_SCRIPT, "scriptGetCustomFuncToken 3" );
if (object)
{
debug( LOG_SCRIPT, "scriptGetCustomFuncToken: object" );
return OBJ_FUNC_CUST;
}
else
{
switch (psFunc->retType)
{
case VAL_BOOL:
debug( LOG_SCRIPT, "scriptGetCustomFuncToken: VAL_BOOL" );
return BOOL_FUNC_CUST;
break;
case VAL_INT:
// case VAL_FLOAT:
debug( LOG_SCRIPT, "scriptGetCustomFuncToken: VAL_INT" );
return NUM_FUNC_CUST;
break;
case VAL_STRING: /* <NEW> */
debug( LOG_SCRIPT, "scriptGetCustomFuncToken: VAL_STRING" );
return STRING_FUNC_CUST;
break;
case VAL_VOID:
debug( LOG_SCRIPT, "scriptGetCustomFuncToken: void function" );
return VOID_FUNC_CUST;
break;
default:
debug( LOG_SCRIPT, "scriptGetCustomFuncToken: default" );
return USER_FUNC_CUST;
break;
}
}
debug( LOG_SCRIPT, "END scriptGetCustomFuncToken" );
}
%}
%option prefix="scr_"
%option nounput
%option yylineno
%x COMMENT
%x SLCOMMENT
%x QUOTE
%%
/* Match to key words */
/*begin return START;*/
/*end return END;*/
wait return WAIT;
every return EVERY;
trigger return TRIGGER;
event return EVENT;
inactive return INACTIVE;
init return INITIALISE;
link return LINK;
ref return REF;
/* new stuff */
function return FUNCTION;
return return RETURN;
public { scr_lval.stype = ST_PUBLIC; return STORAGE; }
private { scr_lval.stype = ST_PRIVATE; return STORAGE; }
while return WHILE;
if return IF;
else return ELSE;
exit return EXIT;
pause return PAUSE;
/* Match to type key words */
bool { scr_lval.tval = VAL_BOOL; return TYPE; }
BOOL { scr_lval.tval = VAL_BOOL; return TYPE; }
int { scr_lval.tval = VAL_INT; return TYPE; }
INT { scr_lval.tval = VAL_INT; return TYPE; }
/* return value for void functions */
void { scr_lval.tval = VAL_VOID; return TYPE; }
VOID { scr_lval.tval = VAL_VOID; return TYPE; }
/* string type isn't implemented yet */
/* string { ais_lval.tval = VAL_STRING; return TYPE; } */
/* object { scr_lval.tval = VAL_OBJECT; return TYPE; } */
/* Match boolean values */
TRUE { scr_lval.bval = TRUE; return BOOLEAN_T; }
true { scr_lval.bval = TRUE; return BOOLEAN_T; }
FALSE { scr_lval.bval = FALSE; return BOOLEAN_T; }
false { scr_lval.bval = FALSE; return BOOLEAN_T; }
/* Match boolean operators */
"==" return BOOLEQUAL;
"!=" return NOTEQUAL;
">=" return GREATEQUAL;
"<=" return LESSEQUAL;
">" return GREATER;
"<" return LESS;
and return _AND;
AND return _AND;
or return _OR;
OR return _OR;
not return _NOT;
NOT return _NOT;
/* Match floating point numbers */
/*-?[0-9]*"."[0-9]+ { scr_lval.fval = (float)atof(scr_text); return FLOAT; }*/
/* Match integer numbers */
-?[0-9]+ { scr_lval.ival = atol(scr_text); return INTEGER; }
/* Match identifiers */
[a-zA-Z][0-9_a-zA-Z]* {
/* See if this identifier has been defined as a type */
if (scriptLookUpType(scr_text, &scr_lval.tval))
{
DBP0(("[lex] TYPE\n"));
return TYPE;
}
/* See if this identifier has been defined as a variable */
else if (scriptLookUpVariable(scr_text, &scr_lval.vSymbol))
{
DBP0(("[lex] variable\n"));
return scriptGetVarToken(scr_lval.vSymbol);
}
/* See if this identifier has been defined as a constant */
else if (scriptLookUpConstant(scr_text, &scr_lval.cSymbol))
{
DBP0(("[lex] constant\n"));
return scriptGetConstToken(scr_lval.cSymbol);
}
/* See if this identifier has been defined as a function */
else if (scriptLookUpFunction(scr_text, &scr_lval.fSymbol))
{
DBP0(("[lex] func\n"));
return scriptGetFuncToken(scr_lval.fSymbol);
}
/* See if this identifier has been defined as a custom function */
else if (scriptLookUpCustomFunction(scr_text, &scr_lval.eSymbol))
{
debug( LOG_SCRIPT, "scriptLookUpCustomFunction: '%s' - custom function", scr_text );
return scriptGetCustomFuncToken(scr_lval.eSymbol);
}
else if (scriptLookUpTrigger(scr_text, &scr_lval.tSymbol))
{
DBP0(("[lex] TRIG_SYM\n"));
return TRIG_SYM;
}
else if (scriptLookUpEvent(scr_text, &scr_lval.eSymbol))
{
DBP0(("[lex] EVENT_SYM\n"));
return EVENT_SYM;
}
else if (scriptLookUpCallback(scr_text, &scr_lval.cbSymbol))
{
DBP0(("[lex] CALLBACK_SYM\n"));
return CALLBACK_SYM;
}
else
{
strcpy(aText[currText], scr_text);
scr_lval.sval = aText[currText];
currText = (currText + 1) % TEXT_BUFFERS;
DBP0(("[lex] IDENT\n"));
return IDENT;
}
}
/* Match quoted text */
\" { BEGIN QUOTE; }
<QUOTE>\" { BEGIN 0; }
<QUOTE>[^\"\n]* {
strcpy(aText[currText], scr_text);
scr_lval.sval = aText[currText];
currText = (currText + 1) % TEXT_BUFFERS;
return QTEXT;
}
/* Skip white space */
[ \t\n\x0d\x0a] ;
/* Strip comments */
"/*" { inComment=TRUE; BEGIN COMMENT; }
<COMMENT>"*/" |
<COMMENT>"*/"\n { inComment=FALSE; BEGIN 0; }
<COMMENT>. |
<COMMENT>\n ;
/* Strip single line comments */
"//" { BEGIN SLCOMMENT; }
<SLCOMMENT>\n { BEGIN 0; }
<SLCOMMENT>[^\n]* ;
/* Match anything that's been missed and pass it as a char */
. return scr_text[0];
%%
/* Set the current input buffer for the lexer */
void scriptSetInputBuffer(UBYTE *pBuffer, UDWORD size)
{
pInputBuffer = pBuffer;
pEndBuffer = pBuffer + size;
/* Reset the lexer in case it's been used before */
scr__flush_buffer( YY_CURRENT_BUFFER );
}
void scriptGetErrorData(int *pLine, char **ppText)
{
*pLine = scr_lineno;
*ppText = scr_text;
}
int scr_wrap(void)
{
if (inComment)
{
DBERROR(("Warning: reched end of file in a comment"));
}
return 1;
}

File diff suppressed because it is too large Load Diff