Scripting engine update:

-implemented string support
-functions can now have arguments, example:
function STRING myFunc(DROID myDroid, int myInt2){<code>}
-functions can have return values:
return <statement>;
or just "return;" for void functions
-function calls are made the normal c/c++ way (using the function from the first example):
myString = myFunc(myDroid, 156);

git-svn-id: svn+ssh://svn.gna.org/svn/warzone/trunk@583 4a71c877-e1ca-e34f-864e-861f7616d084
master
Roman C 2006-08-19 13:26:11 +00:00
parent 77ed8b86a7
commit 92284dc7bc
12 changed files with 1706 additions and 582 deletions

View File

@ -14,6 +14,7 @@
#include "interp.h"
#include "script.h"
#include "event.h"
#include "scripttabs.h" //because of ST_GROUP
// array to store release functions
static VAL_CREATE_FUNC *asCreateFuncs;
@ -87,16 +88,19 @@ BOOL eventInitialise(EVENT_INIT *psInit)
// Create the value heap
if (!HEAP_CREATE(&psValHeap, sizeof(VAL_CHUNK), psInit->valInit, psInit->valExt))
{
debug(LOG_ERROR, "eventInitialise: HEAP_CREATE failed for values");
return FALSE;
}
// Create the trigger heap
if (!HEAP_CREATE(&psTrigHeap, sizeof(ACTIVE_TRIGGER), psInit->trigInit, psInit->trigExt))
{
debug(LOG_ERROR, "eventInitialise: HEAP_CREATE failed for triggers");
return FALSE;
}
// Create the context heap
if (!HEAP_CREATE(&psContHeap, sizeof(SCRIPT_CONTEXT), psInit->contInit, psInit->contExt))
{
debug(LOG_ERROR, "eventInitialise: HEAP_CREATE failed for context");
return FALSE;
}
@ -303,19 +307,22 @@ void eventPrintTriggerInfo(ACTIVE_TRIGGER *psTrigger)
// Initialise the create/release function array - specify the maximum value type
BOOL eventInitValueFuncs(SDWORD maxType)
{
if(asReleaseFuncs != NULL) //<NEW> 13.05.05
debug(LOG_ERROR, "eventInitValueFuncs: array already initialised");
ASSERT((asReleaseFuncs == NULL,
"eventInitValueFuncs: array already initialised"));
asCreateFuncs = (VAL_CREATE_FUNC *)MALLOC(sizeof(VAL_CREATE_FUNC) * maxType);
if (!asCreateFuncs)
{
DBERROR(("eventInitValueFuncs: Out of memory"));
debug(LOG_ERROR, "eventInitValueFuncs: Out of memory");
return FALSE;
}
asReleaseFuncs = (VAL_RELEASE_FUNC *)MALLOC(sizeof(VAL_RELEASE_FUNC) * maxType);
if (!asReleaseFuncs)
{
DBERROR(("eventInitValueFuncs: Out of memory"));
debug(LOG_ERROR, "eventInitValueFuncs: Out of memory");
return FALSE;
}
@ -331,7 +338,7 @@ BOOL eventAddValueCreate(INTERP_TYPE type, VAL_CREATE_FUNC create)
{
if (type >= numFuncs)
{
DBERROR(("eventAddValueCreate: type out of range"));
debug(LOG_ERROR, "eventAddValueCreate: type out of range");
return FALSE;
}
@ -345,6 +352,7 @@ BOOL eventAddValueRelease(INTERP_TYPE type, VAL_RELEASE_FUNC release)
{
if (type >= numFuncs)
{
debug(LOG_ERROR, "eventAddValueRelease: type out of range");
DBERROR(("eventAddValueRelease: type out of range"));
return FALSE;
}
@ -415,9 +423,9 @@ BOOL eventNewContext(SCRIPT_CODE *psCode, CONTEXT_RELEASE release,
//initialize Strings and integers
if(type == VAL_STRING)
{
debug(LOG_SCRIPT,"eventNewContext: STRING type variables are not implemented");
//debug(LOG_ERROR,"eventNewContext: STRING type variables are not implemented");
psCode->ppsLocalVarVal[i][j].v.sval = (char*)MALLOC(255); //TODO: MAXSTRLEN
psCode->ppsLocalVarVal[i][j].v.sval = (char*)MALLOC(MAXSTRLEN);
strcpy(psCode->ppsLocalVarVal[i][j].v.sval,"\0");
}
else
@ -474,7 +482,21 @@ BOOL eventNewContext(SCRIPT_CODE *psCode, CONTEXT_RELEASE release,
type = psCode->pGlobals[val];
}
psNewChunk->asVals[storeIndex].type = type;
psNewChunk->asVals[storeIndex].v.ival = 0;
//initialize Strings
if(type == VAL_STRING)
{
//debug(LOG_ERROR, "eventNewContext: STRING data type is not implemented");
psNewChunk->asVals[storeIndex].v.sval = (char*)MALLOC(MAXSTRLEN);
strcpy(psNewChunk->asVals[storeIndex].v.sval,"\0");
}
else
{
psNewChunk->asVals[storeIndex].v.ival = 0;
}
if (asCreateFuncs != NULL && type < numFuncs && asCreateFuncs[type])
{
if (!asCreateFuncs[type](psNewChunk->asVals + storeIndex))
@ -1377,3 +1399,47 @@ BOOL eventSetTraceLevel(void)
return TRUE;
}
//reset local vars
BOOL resetLocalVars(SCRIPT_CODE *psCode, UDWORD EventIndex)
{
SDWORD i;
if(EventIndex >= psCode->numEvents)
{
debug(LOG_ERROR, "resetLocalVars: wrong event index: %d", EventIndex);
return FALSE;
}
for(i=0; i < psCode->numLocalVars[EventIndex]; i++)
{
//Initialize main value
if(psCode->ppsLocalVarVal[EventIndex][i].type == VAL_STRING)
{
//debug(LOG_ERROR , "resetLocalVars: String type is not implemented");
psCode->ppsLocalVarVal[EventIndex][i].v.sval = (char*)MALLOC(MAXSTRLEN);
strcpy(psCode->ppsLocalVarVal[EventIndex][i].v.sval,"\0");
}
else
{
psCode->ppsLocalVarVal[EventIndex][i].v.ival = 0;
}
/* only group (!) must be re-created each time */
if (psCode->ppsLocalVarVal[EventIndex][i].type == ST_GROUP)
{
debug(LOG_SCRIPT, "resetLocalVars - created");
if (!asCreateFuncs[psCode->ppsLocalVarVal[EventIndex][i].type](&(psCode->ppsLocalVarVal[EventIndex][i]) ))
{
debug(LOG_ERROR, "asCreateFuncs failed for local var (re-init)");
return FALSE;
}
}
}
//debug(LOG_SCRIPT, "Reset local vars for event %d", EventIndex);
return TRUE;
}

View File

@ -95,5 +95,8 @@ extern BOOL eventLoadTrigger(UDWORD time, SCRIPT_CONTEXT *psContext,
//resets the event timer - updateTime
extern void eventTimeReset(UDWORD initTime);
extern STRING *eventGetEventID(SCRIPT_CODE *psCode, SDWORD event);
extern STRING *eventGetTriggerID(SCRIPT_CODE *psCode, SDWORD trigger);
#endif

View File

@ -12,12 +12,15 @@
#include "stack.h"
#include "codeprint.h"
#include "script.h"
#include "event.h" //needed for eventGetEventID()
// the maximum number of instructions to execute before assuming
// an infinite loop
#define INTERP_MAXINSTRUCTIONS 100000
/* The size of each opcode */
SDWORD aOpSize[] =
{
@ -202,50 +205,6 @@ BOOL interpInitialise(void)
return TRUE;
}
//reset local vars
BOOL resetLocalVars(SCRIPT_CODE *psCode, UDWORD EventIndex)
{
SDWORD i;
if(EventIndex >= psCode->numEvents)
{
debug(LOG_ERROR, "resetLocalVars: wrong event index: %d", EventIndex);
return FALSE;
}
for(i=0; i < psCode->numLocalVars[EventIndex]; i++)
{
//Initialize main value
if(psCode->ppsLocalVarVal[EventIndex][i].type == VAL_STRING)
{
debug(LOG_ERROR , "resetLocalVars: String type is not implemented");
psCode->ppsLocalVarVal[EventIndex][i].v.sval = (char*)MALLOC(255); //MAXSTRLEN
strcpy(psCode->ppsLocalVarVal[EventIndex][i].v.sval,"\0");
}
else
{
psCode->ppsLocalVarVal[EventIndex][i].v.ival = 0;
}
/* only group (!) must be re-created each time */
//if (psCode->ppsLocalVarVal[EventIndex][i].type == ST_GROUP)
//{
// //DB_INTERP(("resetLocalVars - created\n"));
//
// if (!asCreateFuncs[psCode->ppsLocalVarVal[EventIndex][i].type](&(psCode->ppsLocalVarVal[EventIndex][i]) ))
// {
// debug(LOG_ERROR, "asCreateFuncs failed for local var (re-init)");
// return FALSE;
// }
//}
}
//debug(LOG_SCRIPT, "Reset local vars for event %d", EventIndex);
return TRUE;
}
/* Run a compiled script */
BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD index, UDWORD offset)
{
@ -262,6 +221,10 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
UDWORD CurEvent;
BOOL bStop,bEvent;
SDWORD callDepth;
STRING *pTrigLab, *pEventLab;
//debug(LOG_SCRIPT, "interpRunScript 1");
ASSERT((PTRVALID(psContext, sizeof(SCRIPT_CONTEXT)),
"interpRunScript: invalid context pointer"));
@ -338,6 +301,8 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
CurEvent = index;
bStop = FALSE;
//debug(LOG_SCRIPT, "interpRunScript 2");
while(!bStop)
{
// Run the code
@ -698,17 +663,20 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
}
break;
case OP_CALL:
TRCPRINTF(("CALL "));
//debug(LOG_SCRIPT, "OP_CALL");
TRCPRINTFUNC( (SCRIPT_FUNC)(*(ip+1)) );
TRCPRINTF(("\n"));
scriptFunc = (SCRIPT_FUNC)*(ip+1);
//debug(LOG_SCRIPT, "OP_CALL 1");
if (!scriptFunc())
{
debug( LOG_ERROR, "interpRunScript: could not do func" );
ASSERT((FALSE, "interpRunScript: could not do func"));
goto exit_with_error;
}
//debug(LOG_SCRIPT, "OP_CALL 2");
ip += aOpSize[opcode];
//debug(LOG_SCRIPT, "OP_CALL 3");
break;
case OP_VARCALL:
TRCPRINTF(("VARCALL "));
@ -808,7 +776,7 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
}
//debug(LOG_SCRIPT, "interpRunScript 3");
TRCPRINTF(("%-6d EXIT\n", ip - psProg->pCode));
@ -819,6 +787,35 @@ BOOL interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD i
exit_with_error:
// Deal with the script crashing or running out of memory
debug(LOG_ERROR,"interpRunScript: *** ERROR EXIT *** (CurEvent=%d)", CurEvent);
debug(LOG_ERROR,"Original event/trigger ID: %d (of %d)", index, psProg->numEvents);
debug(LOG_ERROR,"Current event ID: %d (of %d)", CurEvent, psProg->numEvents);
callDepth = GetCallDepth();
debug(LOG_ERROR,"Call depth : %d", callDepth);
if(psProg->psDebug != NULL)
{
debug(LOG_ERROR,"Displaying debug info:");
if(bEvent)
{
// find the debug info for the original (caller) event
pEventLab = eventGetEventID(psProg, index);
debug(LOG_ERROR,"Original event name: %s", pEventLab);
pEventLab = eventGetEventID(psProg, CurEvent);
debug(LOG_ERROR,"Current event name: %s", pEventLab);
}
else
{
// find the debug info for the trigger
pTrigLab = eventGetTriggerID(psProg, index);
debug(LOG_ERROR,"Trigger: %s", pTrigLab);
}
}
TRCPRINTF(("*** ERROR EXIT ***\n"));
bInterpRunning = FALSE;
return FALSE;

View File

@ -6,6 +6,13 @@
#ifndef _interp_h
#define _interp_h
//String support
//-----------------------------
static UDWORD CURSTACKSTR = 0; //Points to the top of the string stack
#define MAXSTRLEN 255 //Max len of a single string
#define MAXSTACKLEN 6000
static char STRSTACK[MAXSTACKLEN][MAXSTRLEN]; //simple string 'stack'
/* The possible value types for scripts */
typedef enum _interp_type
{
@ -96,6 +103,9 @@ typedef enum _op_code
OP_OR,
OP_NOT,
//String cancatenation
OP_CANC,
// Comparison operators
OP_EQUAL,
OP_NOTEQUAL,
@ -107,7 +117,7 @@ typedef enum _op_code
OP_FUNC, //custom (in-script) function call
OP_POPLOCAL, //local var
OP_PUSHLOCAL,
OP_PUSHLOCALREF,
OP_PUSHLOCALREF, //variable of object type (pointer)
} OPCODE;
/* How far the opcode is shifted up a UDWORD to allow other data to be

View File

@ -122,6 +122,7 @@ typedef struct _const_symbol
BOOL bval;
SDWORD ival;
void *oval;
STRING *sval; //String values
// float fval;
} CONST_SYMBOL;
@ -309,5 +310,9 @@ extern BOOL scriptLookUpFunction(STRING *pIdent, FUNC_SYMBOL **ppsSym);
/* Look up an in-script custom function symbol */
extern BOOL scriptLookUpCustomFunction(STRING *pIdent, EVENT_SYMBOL **ppsSym);
extern BOOL popArguments(UDWORD **ip_temp, SDWORD numParams);
extern void widgCopyString(STRING *pDest, STRING *pSrc);
#endif

View File

@ -44,8 +44,6 @@ SDWORD scriptGetVarToken(VAR_SYMBOL *psVar)
{
BOOL object;
//debug( LOG_SCRIPT, "scriptGetVarToken" );
// See if this is an object pointer
if (!asScrTypeTab || psVar->type < VAL_USERTYPESTART)
{
@ -120,17 +118,17 @@ SDWORD scriptGetVarToken(VAR_SYMBOL *psVar)
break;
case VAL_INT:
// case VAL_FLOAT:
//debug( LOG_SCRIPT, "scriptGetVarToken: VAL_INT (NUM_VAR)" );
return NUM_VAR;
break;
case VAL_STRING:
return STRING_VAR;
break;
default:
return VAR;
break;
}
}
}
//debug( LOG_SCRIPT, "END scriptGetVarToken" );
}
/* Get the token type for a constant symbol */
@ -138,8 +136,6 @@ SDWORD scriptGetConstToken(CONST_SYMBOL *psConst)
{
BOOL object;
//debug( LOG_SCRIPT, "scriptGetConstToken" );
// See if this is an object constant
if (!asScrTypeTab || psConst->type < VAL_USERTYPESTART)
{
@ -159,9 +155,13 @@ SDWORD scriptGetConstToken(CONST_SYMBOL *psConst)
// case VAL_FLOAT:
return NUM_CONSTANT;
break;
case VAL_STRING:
return STRING_CONSTANT;
break;
default:
if (object)
{
//debug(LOG_SCRIPT, "scriptGetConstToken: OBJ_CONSTANT");
return OBJ_CONSTANT;
}
else
@ -170,8 +170,6 @@ SDWORD scriptGetConstToken(CONST_SYMBOL *psConst)
}
break;
}
//debug( LOG_SCRIPT, "END scriptGetConstToken" );
}
/* Get the token type for a function symbol */
@ -179,17 +177,8 @@ SDWORD scriptGetFuncToken(FUNC_SYMBOL *psFunc)
{
BOOL object;
//debug( LOG_SCRIPT, "scriptGetFuncToken" );
// 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;
}
object = asScrTypeTab[psFunc->type - VAL_USERTYPESTART].accessType == AT_OBJECT;
if (object)
{
@ -206,6 +195,9 @@ SDWORD scriptGetFuncToken(FUNC_SYMBOL *psFunc)
// case VAL_FLOAT:
return NUM_FUNC;
break;
case VAL_STRING:
return STRING_FUNC;
break;
case VAL_VOID:
return FUNC;
break;
@ -214,26 +206,18 @@ SDWORD scriptGetFuncToken(FUNC_SYMBOL *psFunc)
break;
}
}
//debug( LOG_SCRIPT, "END scriptGetFuncToken" );
}
/* 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
@ -241,30 +225,23 @@ SDWORD scriptGetCustomFuncToken(EVENT_SYMBOL *psFunc)
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" );
case 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" );
}
@ -291,10 +268,12 @@ inactive return INACTIVE;
init return INITIALISE;
link return LINK;
ref return REF;
return return RET;
function return FUNCTION;
/* function return FUNCTION;*/
/* cond return COND; */
/* new stuff */
function return FUNCTION;
return { return RET; }
public { scr_lval.stype = ST_PUBLIC; return STORAGE; }
private { scr_lval.stype = ST_PRIVATE; return STORAGE; }
@ -306,15 +285,15 @@ exit return EXIT;
pause return PAUSE;
/* Match to type key words */
void { scr_lval.tval = VAL_VOID; return TYPE; }
VOID { scr_lval.tval = VAL_VOID; return TYPE; }
string { scr_lval.tval = VAL_STRING; return TYPE; }
STRING { scr_lval.tval = VAL_STRING; return TYPE; }
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; }
/*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; } */
@ -346,64 +325,63 @@ NOT return _NOT;
-?[0-9]+ { scr_lval.ival = atol(scr_text); return INTEGER; }
/* Match identifiers */
[a-zA-Z][0-9_a-zA-Z]* {
//debug( LOG_SCRIPT, "FLEX: looking up '%s'", scr_text );
[a-zA-Z_][0-9_a-zA-Z_]* {
debug(LOG_SCRIPT, "looking up '%s'", scr_text);
/* See if this identifier has been defined as a type */
if (scriptLookUpType(scr_text, &scr_lval.tval))
{
DBP0(("[lex] TYPE\n"));
debug(LOG_SCRIPT, "'%s' is a type", scr_text);
return TYPE;
}
/* See if this identifier has been defined as a variable */
else if (scriptLookUpVariable(scr_text, &scr_lval.vSymbol))
{
DBP0(("[lex] variable\n"));
debug(LOG_SCRIPT, "'%s' is a var", scr_text);
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"));
debug(LOG_SCRIPT, "'%s' is a constant", scr_text);
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"));
debug(LOG_SCRIPT, "'%s' is a function", scr_text);
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 );
debug(LOG_SCRIPT, "'%s' is a cust func", scr_text);
return scriptGetCustomFuncToken(scr_lval.eSymbol);
}
else if (scriptLookUpTrigger(scr_text, &scr_lval.tSymbol))
{
DBP0(("[lex] TRIG_SYM\n"));
debug(LOG_SCRIPT, "'%s' is a trigger", scr_text);
return TRIG_SYM;
}
else if (scriptLookUpEvent(scr_text, &scr_lval.eSymbol))
{
DBP0(("[lex] EVENT_SYM\n"));
debug(LOG_SCRIPT, "'%s' is an event", scr_text);
return EVENT_SYM;
}
else if (scriptLookUpCallback(scr_text, &scr_lval.cbSymbol))
{
DBP0(("[lex] CALLBACK_SYM\n"));
debug(LOG_SCRIPT, "'%s' is a callback", scr_text);
return CALLBACK_SYM;
}
else
{
//debug( LOG_SCRIPT, "FLEX: '%s' is an ident", scr_text );
debug(LOG_SCRIPT, "'%s' is an ident", scr_text);
strcpy(aText[currText], scr_text);
scr_lval.sval = aText[currText];
currText = (currText + 1) % TEXT_BUFFERS;
DBP0(("[lex] IDENT\n"));
return IDENT;
}
}
@ -415,6 +393,7 @@ NOT return _NOT;
strcpy(aText[currText], scr_text);
scr_lval.sval = aText[currText];
currText = (currText + 1) % TEXT_BUFFERS;
debug(LOG_SCRIPT, "%s is QTEXT", scr_text);
return QTEXT;
}
@ -458,7 +437,7 @@ int scr_wrap(void)
{
if (inComment)
{
DBERROR(("Warning: reched end of file in a comment"));
DBERROR(("Warning: reached end of file in a comment"));
}
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -12,10 +12,13 @@
#include "codeprint.h"
#include "script.h"
#include "script_parser.h"
/* number of values in each stack chunk */
#define INIT_SIZE 15
#define EXT_SIZE 2
/* store for a 'chunk' of the stack */
typedef struct _stack_chunk
{
@ -92,6 +95,15 @@ BOOL stackPush(INTERP_VAL *psVal)
valid space */
memcpy(&(psCurrChunk->aVals[currEntry]), psVal, sizeof(INTERP_VAL));
/* String support: Copy the string, otherwise the stack will operate directly on the
original string (like & opcode will actually store the result in the first
variable which would point to the original string) */
if(psVal->type == VAL_STRING)
{
psCurrChunk->aVals[currEntry].v.sval = (char*)MALLOC(MAXSTRLEN);
strcpy(psCurrChunk->aVals[currEntry].v.sval,psVal->v.sval);
}
/* Now update psCurrChunk and currEntry */
currEntry++;
if (currEntry == psCurrChunk->size)
@ -100,6 +112,7 @@ BOOL stackPush(INTERP_VAL *psVal)
if (!stackNewChunk(EXT_SIZE))
{
/* Out of memory */
debug(LOG_ERROR, "stackPush: Out of memory");
return FALSE;
}
}
@ -114,6 +127,7 @@ BOOL stackPop(INTERP_VAL *psVal)
{
if ((psCurrChunk->psPrev == NULL) && (currEntry == 0))
{
debug(LOG_ERROR, "stackPop: stack empty");
ASSERT((FALSE, "stackPop: stack empty"));
return FALSE;
}
@ -171,11 +185,39 @@ BOOL stackPopType(INTERP_VAL *psVal)
//debug(LOG_SCRIPT, "stackPopType 4");
if (!interpCheckEquiv(psVal->type,psTop->type))
//String support
if(psVal->type == VAL_STRING) //If we are about to assign something to a string variable (psVal)
{
debug(LOG_ERROR, "stackPopType: type mismatch");
ASSERT((FALSE, "stackPopType: type mismatch"));
return FALSE;
if(psTop->type != VAL_STRING) //if assigning a non-string to a string, then convert it
{
/* Check for compatible types */
if((psTop->type == VAL_INT) || (psTop->type == VAL_BOOL))
{
STRING *tempstr;
tempstr = (char*)MALLOC(MAXSTRLEN);
sprintf(tempstr, "%d", psTop->v.ival);
psVal->v.sval = tempstr;
}
else
{
debug(LOG_ERROR, "stackPopType: trying to assign an incompatible data type to a string variable (type = %d)", psTop->type);
return FALSE;
}
}
else //Assigning a string to a string, just do the default action
{
psVal->v.ival = psTop->v.ival;
}
}
else // we are about to assign something to a non-string variable (psVal)
{
if (!interpCheckEquiv(psVal->type,psTop->type))
{
debug(LOG_ERROR, "stackPopType: type mismatch");
ASSERT((FALSE, "stackPopType: type mismatch"));
return FALSE;
}
}
//debug(LOG_SCRIPT, "stackPopType 5");
@ -202,6 +244,8 @@ BOOL stackPopParams(SDWORD numParams, ...)
UDWORD index, params;
STACK_CHUNK *psCurr;
//debug(LOG_SCRIPT,"stackPopParams");
va_start(args, numParams);
// Find the position of the first parameter, and set
@ -232,12 +276,19 @@ BOOL stackPopParams(SDWORD numParams, ...)
}
}
}
//debug(LOG_SCRIPT,"stackPopParams 1");
if (!psCurr)
{
debug(LOG_ERROR,"stackPopParams: not enough parameters on stack");
ASSERT((FALSE, "stackPopParams: not enough parameters on stack"));
return FALSE;
}
//debug(LOG_SCRIPT,"stackPopParams 2");
//string support
// Get the values, checking their types
index = currEntry;
for (i=0; i< numParams; i++)
@ -245,14 +296,45 @@ BOOL stackPopParams(SDWORD numParams, ...)
type = va_arg(args, int);
pData = va_arg(args, UDWORD *);
//debug(LOG_SCRIPT,"stackPopParams 3 (%d parameter)", i);
psVal = psCurr->aVals + index;
if (!interpCheckEquiv(type,psVal->type))
if(type != VAL_STRING) //Allow param to be any type, if function expects a string (auto-convert later)
{
ASSERT((FALSE, "stackPopParams: type mismatch"));
va_end(args);
return FALSE;
//debug(LOG_SCRIPT,"stackPopParams 4 - non string");
if (!interpCheckEquiv(type,psVal->type))
{
ASSERT((FALSE, "stackPopParams: type mismatch"));
va_end(args);
return FALSE;
}
*pData = (UDWORD)psVal->v.ival;
}
else //TODO: allow only compatible types
{
//debug(LOG_SCRIPT,"stackPopParams 5 - string");
if(psVal->type == VAL_STRING) //Passing a String
{
//debug(LOG_SCRIPT, "stackPopParams - string");
*pData = (UDWORD)psVal->v.ival;
debug(LOG_SCRIPT, "%s",*pData);
}
else //Integer
{
STRING *tempstr;
//debug(LOG_SCRIPT, "stackPopParams - non string");
tempstr = (char*)MALLOC(MAXSTRLEN);
sprintf(tempstr, "%d", psVal->v.ival);
*pData = tempstr;
//itoa(psVal->v.ival,tmpstr,10);
}
}
*pData = (UDWORD)psVal->v.ival;
index += 1;
if (index >= psCurr->size)
@ -262,6 +344,8 @@ BOOL stackPopParams(SDWORD numParams, ...)
}
}
//debug(LOG_SCRIPT,"END stackPopParams");
va_end(args);
return TRUE;
}
@ -356,6 +440,7 @@ BOOL stackBinaryOp(OPCODE opcode)
// Get the parameters
if (psCurrChunk->psPrev == NULL && currEntry < 2)
{
debug(LOG_ERROR, "stackBinaryOp: not enough entries on stack");
ASSERT((FALSE, "stackBinaryOp: not enough entries on stack"));
return FALSE;
}
@ -383,10 +468,14 @@ BOOL stackBinaryOp(OPCODE opcode)
psV2 = psCurrChunk->aVals + psCurrChunk->size - 1;
}
if (!interpCheckEquiv(psV1->type, psV2->type))
if(opcode != OP_CANC) //string - Don't check if OP_CANC, since types can be mixed here
{
ASSERT((FALSE, "stackBinaryOp: type mismatch"));
return FALSE;
if (!interpCheckEquiv(psV1->type, psV2->type))
{
debug(LOG_ERROR, "stackBinaryOp: type mismatch");
ASSERT((FALSE, "stackBinaryOp: type mismatch"));
return FALSE;
}
}
// do the operation
@ -434,7 +523,53 @@ BOOL stackBinaryOp(OPCODE opcode)
psV1->type = VAL_BOOL;
psV1->v.bval = psV1->v.ival < psV2->v.ival;
break;
case OP_CANC: //String cancatenation
{
char *tempstr1[MAXSTRLEN];
char *tempstr2[MAXSTRLEN];
/* Check first value if it's compatible with Strings */
if((psV1->type == VAL_INT) || (psV1->type == VAL_BOOL)) //First value isn't string, but can be converted to string
{
sprintf(tempstr1,"%d",psV1->v.ival); //Convert
psV1->type = VAL_STRING; //Mark as string now
}
else if(psV1->type == VAL_STRING) //Is a string
{
strcpy(tempstr1,psV1->v.sval);
}
else
{
debug(LOG_ERROR, "stackBinaryOp: OP_CANC: first parameter is not compatible with Strings");
return FALSE;
}
/* Check first value if it's compatible with Strings */
if((psV2->type == VAL_INT) || (psV2->type == VAL_BOOL))
{
sprintf(tempstr2,"%d",psV2->v.ival); //Convert
}
else if(psV2->type == VAL_STRING) //Is a string
{
strcpy(tempstr2,psV2->v.sval);
}
else
{
debug(LOG_ERROR, "stackBinaryOp: OP_CANC: first parameter is not compatible with Strings");
return FALSE;
}
strcat(tempstr1,tempstr2);
strcpy(psV1->v.sval,tempstr1); //Assign
psV1->type = VAL_STRING;
}
break;
default:
debug(LOG_ERROR, "stackBinaryOp: unknown opcode");
ASSERT((FALSE, "stackBinaryOp: unknown opcode"));
return FALSE;
break;
@ -512,12 +647,14 @@ BOOL stackInitialise(void)
psStackBase = (STACK_CHUNK *)MALLOC(sizeof(STACK_CHUNK));
if (psStackBase == NULL)
{
debug(LOG_ERROR, "Out of memory");
DBERROR(("Out of memory"));
return FALSE;
}
psStackBase->aVals = MALLOC(sizeof(INTERP_VAL) * INIT_SIZE);
if (!psStackBase->aVals)
{
debug(LOG_ERROR, "Out of memory");
DBERROR(("Out of memory"));
return FALSE;
}
@ -527,6 +664,9 @@ BOOL stackInitialise(void)
psStackBase->psNext = NULL;
psCurrChunk = psStackBase;
//string support
CURSTACKSTR = 0; //initialize string 'stack'
return TRUE;
}

View File

@ -46,4 +46,6 @@ extern BOOL stackUnaryOp(OPCODE opcode);
/* Reset the stack to an empty state */
extern void stackReset(void);
#endif

View File

@ -6405,3 +6405,35 @@ BOOL scrEnumDroid(void)
return TRUE;
}
//-----------------------------------------
//New functions
//-----------------------------------------
//compare two strings (0 means they are different)
BOOL scrStrcmp(void)
{
STRING *ssval1=NULL;
STRING *ssval2=NULL;
debug(LOG_SCRIPT,"scrStrcmp");
if (!stackPopParams(2, VAL_STRING, &ssval1, VAL_STRING, &ssval2))
{
debug(LOG_ERROR, "scrStrcmp(): stack failed");
return FALSE;
}
debug(LOG_SCRIPT,"scrStrcmp 1");
if (!stackPushResult(VAL_BOOL, !strcmp(ssval1, ssval2)))
{
debug(LOG_ERROR, "scrStrcmp: failed to push result");
return FALSE;
}
debug(LOG_SCRIPT,"scrStrcmp 2");
return TRUE;
}

View File

@ -496,6 +496,11 @@ extern BOOL scrResetLimboMission(void);
// skirmish lassat fire.
extern BOOL scrSkFireLassat(void);
//-----------------------------------------
//New functions
//-----------------------------------------
extern BOOL scrStrcmp(void);
#endif

View File

@ -698,6 +698,13 @@ FUNC_SYMBOL asFuncTable[] =
{ "skFireLassat", scrSkFireLassat, VAL_VOID,
2, {VAL_INT, (INTERP_TYPE)ST_BASEOBJECT } },
/* New functions */
{ "strcmp", scrStrcmp, VAL_BOOL,
2, { VAL_STRING, VAL_STRING} },
/* END new functions */
// { "skOrderDroidLineBuild", scrSkOrderDroidLineBuild, VAL_VOID,
// 6, { (INTERP_TYPE)ST_DROID, (INTERP_TYPE)ST_STRUCTURESTAT, VAL_INT, VAL_INT, VAL_INT, VAL_INT } },