OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [rtems_webserver/] [ejparse.c] - Diff between revs 30 and 173

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 30 Rev 173
/*
/*
 * ejparse.c -- Ejscript(TM) Parser
 * ejparse.c -- Ejscript(TM) Parser
 *
 *
 * Copyright (c) Go Ahead Software, Inc., 1995-1999
 * Copyright (c) Go Ahead Software, Inc., 1995-1999
 *
 *
 * See the file "license.txt" for usage and redistribution license requirements
 * See the file "license.txt" for usage and redistribution license requirements
 */
 */
 
 
/******************************** Description *********************************/
/******************************** Description *********************************/
 
 
/*
/*
 *      Ejscript parser. This implementes a subset of the JavaScript language.
 *      Ejscript parser. This implementes a subset of the JavaScript language.
 *      Multiple Ejscript parsers can be opened at a time.
 *      Multiple Ejscript parsers can be opened at a time.
 */
 */
 
 
/********************************** Includes **********************************/
/********************************** Includes **********************************/
 
 
#include        "ej.h"
#include        "ej.h"
 
 
/********************************** Local Data ********************************/
/********************************** Local Data ********************************/
 
 
ej_t                    **ejHandles;                                                    /* List of ej handles */
ej_t                    **ejHandles;                                                    /* List of ej handles */
int                             ejMax = -1;                                                             /* Maximum size of      */
int                             ejMax = -1;                                                             /* Maximum size of      */
 
 
/****************************** Forward Declarations **************************/
/****************************** Forward Declarations **************************/
 
 
static ej_t             *ejPtr(int eid);
static ej_t             *ejPtr(int eid);
static void             clearString(char_t **ptr);
static void             clearString(char_t **ptr);
static void             setString(char_t **ptr, char_t *s);
static void             setString(char_t **ptr, char_t *s);
static void             appendString(char_t **ptr, char_t *s);
static void             appendString(char_t **ptr, char_t *s);
static void             freeVar(sym_t* sp);
static void             freeVar(sym_t* sp);
static int              parse(ej_t *ep, int state, int flags);
static int              parse(ej_t *ep, int state, int flags);
static int              parseStmt(ej_t *ep, int state, int flags);
static int              parseStmt(ej_t *ep, int state, int flags);
static int              parseDeclaration(ej_t *ep, int state, int flags);
static int              parseDeclaration(ej_t *ep, int state, int flags);
static int              parseArgs(ej_t *ep, int state, int flags);
static int              parseArgs(ej_t *ep, int state, int flags);
static int              parseCond(ej_t *ep, int state, int flags);
static int              parseCond(ej_t *ep, int state, int flags);
static int              parseExpr(ej_t *ep, int state, int flags);
static int              parseExpr(ej_t *ep, int state, int flags);
static int              evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs);
static int              evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs);
static int              evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs);
static int              evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs);
static int              evalFunction(ej_t *ep);
static int              evalFunction(ej_t *ep);
static void             freeFunc(ejfunc_t *func);
static void             freeFunc(ejfunc_t *func);
 
 
/************************************* Code ***********************************/
/************************************* Code ***********************************/
/*
/*
 *      Initialize a Ejscript engine
 *      Initialize a Ejscript engine
 */
 */
 
 
int ejOpenEngine(sym_fd_t variables, sym_fd_t functions)
int ejOpenEngine(sym_fd_t variables, sym_fd_t functions)
{
{
        ej_t    *ep;
        ej_t    *ep;
        int             eid, vid;
        int             eid, vid;
 
 
        if ((eid = hAllocEntry((void***) &ejHandles, &ejMax, sizeof(ej_t))) < 0) {
        if ((eid = hAllocEntry((void***) &ejHandles, &ejMax, sizeof(ej_t))) < 0) {
                return -1;
                return -1;
        }
        }
        ep = ejHandles[eid];
        ep = ejHandles[eid];
        ep->eid = eid;
        ep->eid = eid;
 
 
/*
/*
 *      Create a top level symbol table if one is not provided for variables and
 *      Create a top level symbol table if one is not provided for variables and
 *      functions. Variables may create other symbol tables for block level
 *      functions. Variables may create other symbol tables for block level
 *      declarations so we use hAlloc to manage a list of variable tables.
 *      declarations so we use hAlloc to manage a list of variable tables.
 */
 */
        if ((vid = hAlloc((void***) &ep->variables)) < 0) {
        if ((vid = hAlloc((void***) &ep->variables)) < 0) {
                ejMax = hFree((void***) &ejHandles, ep->eid);
                ejMax = hFree((void***) &ejHandles, ep->eid);
                return -1;
                return -1;
        }
        }
        if (vid >= ep->variableMax) {
        if (vid >= ep->variableMax) {
                ep->variableMax = vid + 1;
                ep->variableMax = vid + 1;
        }
        }
 
 
        if (variables == -1) {
        if (variables == -1) {
                ep->variables[vid] = symOpen(64) + EJ_OFFSET;
                ep->variables[vid] = symOpen(64) + EJ_OFFSET;
                ep->flags |= FLAGS_VARIABLES;
                ep->flags |= FLAGS_VARIABLES;
 
 
        } else {
        } else {
                ep->variables[vid] = variables + EJ_OFFSET;
                ep->variables[vid] = variables + EJ_OFFSET;
        }
        }
 
 
        if (functions == -1) {
        if (functions == -1) {
                ep->functions = symOpen(64);
                ep->functions = symOpen(64);
                ep->flags |= FLAGS_FUNCTIONS;
                ep->flags |= FLAGS_FUNCTIONS;
        } else {
        } else {
                ep->functions = functions;
                ep->functions = functions;
        }
        }
 
 
        ejLexOpen(ep);
        ejLexOpen(ep);
 
 
/*
/*
 *      Define standard constants
 *      Define standard constants
 */
 */
        ejSetGlobalVar(ep->eid, T("null"), NULL);
        ejSetGlobalVar(ep->eid, T("null"), NULL);
 
 
#if EMF
#if EMF
        ejEmfOpen(ep->eid);
        ejEmfOpen(ep->eid);
#endif
#endif
        return ep->eid;
        return ep->eid;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Close
 *      Close
 */
 */
 
 
void ejCloseEngine(int eid)
void ejCloseEngine(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
        int             i;
        int             i;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return;
                return;
        }
        }
 
 
#if EMF
#if EMF
        ejEmfClose(eid);
        ejEmfClose(eid);
#endif
#endif
 
 
        bfreeSafe(B_L, ep->error);
        bfreeSafe(B_L, ep->error);
        ep->error = NULL;
        ep->error = NULL;
        bfreeSafe(B_L, ep->result);
        bfreeSafe(B_L, ep->result);
        ep->result = NULL;
        ep->result = NULL;
 
 
        ejLexClose(ep);
        ejLexClose(ep);
 
 
        if (ep->flags & FLAGS_VARIABLES) {
        if (ep->flags & FLAGS_VARIABLES) {
                for (i = ep->variableMax - 1; i >= 0; i--) {
                for (i = ep->variableMax - 1; i >= 0; i--) {
                        symClose(ep->variables[i] - EJ_OFFSET, freeVar);
                        symClose(ep->variables[i] - EJ_OFFSET, freeVar);
                        ep->variableMax = hFree((void***) &ep->variables, i);
                        ep->variableMax = hFree((void***) &ep->variables, i);
                }
                }
        }
        }
        if (ep->flags & FLAGS_FUNCTIONS) {
        if (ep->flags & FLAGS_FUNCTIONS) {
                symClose(ep->functions, freeVar);
                symClose(ep->functions, freeVar);
        }
        }
 
 
        ejMax = hFree((void***) &ejHandles, ep->eid);
        ejMax = hFree((void***) &ejHandles, ep->eid);
        bfree(B_L, ep);
        bfree(B_L, ep);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Callback from symClose. Free the variable.
 *      Callback from symClose. Free the variable.
 */
 */
 
 
static void freeVar(sym_t* sp)
static void freeVar(sym_t* sp)
{
{
        valueFree(&sp->content);
        valueFree(&sp->content);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Evaluate a Ejscript file
 *      Evaluate a Ejscript file
 */
 */
 
 
#if DEV
#if DEV
char_t *ejEvalFile(int eid, char_t *path, char_t **emsg)
char_t *ejEvalFile(int eid, char_t *path, char_t **emsg)
{
{
        gstat_t sbuf;
        gstat_t sbuf;
        ej_t    *ep;
        ej_t    *ep;
        char_t  *script, *rs;
        char_t  *script, *rs;
        char    *fileBuf;
        char    *fileBuf;
        int             fd;
        int             fd;
 
 
        a_assert(path && *path);
        a_assert(path && *path);
 
 
        if (emsg) {
        if (emsg) {
                *emsg = NULL;
                *emsg = NULL;
        }
        }
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return NULL;
                return NULL;
        }
        }
 
 
        if ((fd = gopen(path, O_RDONLY | O_BINARY, 0666)) < 0) {
        if ((fd = gopen(path, O_RDONLY | O_BINARY, 0666)) < 0) {
                ejError(ep, T("Bad handle %d"), eid);
                ejError(ep, T("Bad handle %d"), eid);
                return NULL;
                return NULL;
        }
        }
        if (gstat(path, &sbuf) < 0) {
        if (gstat(path, &sbuf) < 0) {
                close(fd);
                close(fd);
                ejError(ep, T("Cant stat %s"), path);
                ejError(ep, T("Cant stat %s"), path);
                return NULL;
                return NULL;
        }
        }
        if ((fileBuf = balloc(B_L, sbuf.st_size + 1)) == NULL) {
        if ((fileBuf = balloc(B_L, sbuf.st_size + 1)) == NULL) {
                close(fd);
                close(fd);
                ejError(ep, T("Cant malloc %d"), sbuf.st_size);
                ejError(ep, T("Cant malloc %d"), sbuf.st_size);
                return NULL;
                return NULL;
        }
        }
        if (read(fd, fileBuf, sbuf.st_size) != (int)sbuf.st_size) {
        if (read(fd, fileBuf, sbuf.st_size) != (int)sbuf.st_size) {
                close(fd);
                close(fd);
                bfree(B_L, fileBuf);
                bfree(B_L, fileBuf);
                ejError(ep, T("Error reading %s"), path);
                ejError(ep, T("Error reading %s"), path);
                return NULL;
                return NULL;
        }
        }
        fileBuf[sbuf.st_size] = '\0';
        fileBuf[sbuf.st_size] = '\0';
        close(fd);
        close(fd);
 
 
        if ((script = ballocAscToUni(fileBuf)) == NULL) {
        if ((script = ballocAscToUni(fileBuf)) == NULL) {
                bfree(B_L, fileBuf);
                bfree(B_L, fileBuf);
                ejError(ep, T("Cant malloc %d"), sbuf.st_size + 1);
                ejError(ep, T("Cant malloc %d"), sbuf.st_size + 1);
                return NULL;
                return NULL;
        }
        }
        bfree(B_L, fileBuf);
        bfree(B_L, fileBuf);
 
 
        rs = ejEvalBlock(eid, script, emsg);
        rs = ejEvalBlock(eid, script, emsg);
 
 
        bfree(B_L, script);
        bfree(B_L, script);
        return rs;
        return rs;
}
}
#endif
#endif
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Create a new variable scope block so that consecutive ejEval calls may
 *      Create a new variable scope block so that consecutive ejEval calls may
 *      be made with the same varible scope. This space MUST be closed with
 *      be made with the same varible scope. This space MUST be closed with
 *      ejCloseBlock when the evaluations are complete.
 *      ejCloseBlock when the evaluations are complete.
 */
 */
 
 
int ejOpenBlock(int eid)
int ejOpenBlock(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
        int             vid;
        int             vid;
 
 
        if((ep = ejPtr(eid)) == NULL) {
        if((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        if ((vid = hAlloc((void***) &ep->variables)) < 0) {
        if ((vid = hAlloc((void***) &ep->variables)) < 0) {
                return -1;
                return -1;
        }
        }
        if (vid >= ep->variableMax) {
        if (vid >= ep->variableMax) {
                ep->variableMax = vid + 1;
                ep->variableMax = vid + 1;
        }
        }
        ep->variables[vid] = symOpen(64) + EJ_OFFSET;
        ep->variables[vid] = symOpen(64) + EJ_OFFSET;
        return vid;
        return vid;
 
 
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Close a variable scope block. The vid parameter is the return value from
 *      Close a variable scope block. The vid parameter is the return value from
 *      the call to ejOpenBlock
 *      the call to ejOpenBlock
 */
 */
 
 
int ejCloseBlock(int eid, int vid)
int ejCloseBlock(int eid, int vid)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if((ep = ejPtr(eid)) == NULL) {
        if((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        symClose(ep->variables[vid] - EJ_OFFSET, freeVar);
        symClose(ep->variables[vid] - EJ_OFFSET, freeVar);
        ep->variableMax = hFree((void***) &ep->variables, vid);
        ep->variableMax = hFree((void***) &ep->variables, vid);
        return 0;
        return 0;
 
 
}
}
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Create a new variable scope block and evaluate a script. All variables
 *      Create a new variable scope block and evaluate a script. All variables
 *      created during this context will be automatically deleted when complete.
 *      created during this context will be automatically deleted when complete.
 */
 */
 
 
char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg)
char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg)
{
{
        char_t* returnVal;
        char_t* returnVal;
        int             vid;
        int             vid;
 
 
        a_assert(script);
        a_assert(script);
 
 
        vid = ejOpenBlock(eid);
        vid = ejOpenBlock(eid);
        returnVal = ejEval(eid, script, emsg);
        returnVal = ejEval(eid, script, emsg);
        ejCloseBlock(eid, vid);
        ejCloseBlock(eid, vid);
 
 
        return returnVal;
        return returnVal;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Parse and evaluate a Ejscript. The caller may provide a symbol table to
 *      Parse and evaluate a Ejscript. The caller may provide a symbol table to
 *      use for variables and function definitions. Return char_t pointer on
 *      use for variables and function definitions. Return char_t pointer on
 *      success otherwise NULL pointer is returned.
 *      success otherwise NULL pointer is returned.
 */
 */
 
 
char_t *ejEval(int eid, char_t *script, char_t **emsg)
char_t *ejEval(int eid, char_t *script, char_t **emsg)
{
{
        ej_t    *ep;
        ej_t    *ep;
        ejinput_t       *oldBlock;
        ejinput_t       *oldBlock;
        int             state;
        int             state;
 
 
        a_assert(script);
        a_assert(script);
 
 
        if (emsg) {
        if (emsg) {
                *emsg = NULL;
                *emsg = NULL;
        }
        }
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return NULL;
                return NULL;
        }
        }
 
 
        setString(&ep->result, T(""));
        setString(&ep->result, T(""));
 
 
/*
/*
 *      Allocate a new evaluation block, and save the old one
 *      Allocate a new evaluation block, and save the old one
 */
 */
        oldBlock = ep->input;
        oldBlock = ep->input;
        ejLexOpenScript(ep, script);
        ejLexOpenScript(ep, script);
 
 
/*
/*
 *      Do the actual parsing and evaluation
 *      Do the actual parsing and evaluation
 */
 */
        do {
        do {
                state = parse(ep, STATE_BEGIN, FLAGS_EXE);
                state = parse(ep, STATE_BEGIN, FLAGS_EXE);
        } while (state != STATE_EOF && state != STATE_ERR);
        } while (state != STATE_EOF && state != STATE_ERR);
 
 
        ejLexCloseScript(ep);
        ejLexCloseScript(ep);
 
 
/*
/*
 *      Return any error string to the user
 *      Return any error string to the user
 */
 */
        if (state == STATE_ERR && emsg) {
        if (state == STATE_ERR && emsg) {
                *emsg = bstrdup(B_L, ep->error);
                *emsg = bstrdup(B_L, ep->error);
        }
        }
 
 
/*
/*
 *      Restore the old evaluation block
 *      Restore the old evaluation block
 */
 */
        ep->input = oldBlock;
        ep->input = oldBlock;
 
 
        if (state == STATE_EOF) {
        if (state == STATE_EOF) {
                return ep->result;
                return ep->result;
        }
        }
        if (state == STATE_ERR) {
        if (state == STATE_ERR) {
                return NULL;
                return NULL;
        }
        }
        return ep->result;
        return ep->result;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Recursive descent parser for Ejscript
 *      Recursive descent parser for Ejscript
 */
 */
 
 
static int parse(ej_t *ep, int state, int flags)
static int parse(ej_t *ep, int state, int flags)
{
{
        a_assert(ep);
        a_assert(ep);
 
 
        switch (state) {
        switch (state) {
/*
/*
 *      Any statement, function arguments or conditional expressions
 *      Any statement, function arguments or conditional expressions
 */
 */
        case STATE_STMT:
        case STATE_STMT:
        case STATE_DEC:
        case STATE_DEC:
                state = parseStmt(ep, state, flags);
                state = parseStmt(ep, state, flags);
                break;
                break;
 
 
        case STATE_EXPR:
        case STATE_EXPR:
                state = parseStmt(ep, state, flags);
                state = parseStmt(ep, state, flags);
                break;
                break;
 
 
/*
/*
 *      Variable declaration list
 *      Variable declaration list
 */
 */
        case STATE_DEC_LIST:
        case STATE_DEC_LIST:
                state = parseDeclaration(ep, state, flags);
                state = parseDeclaration(ep, state, flags);
                break;
                break;
 
 
/*
/*
 *      Function argument string
 *      Function argument string
 */
 */
        case STATE_ARG_LIST:
        case STATE_ARG_LIST:
                state = parseArgs(ep, state, flags);
                state = parseArgs(ep, state, flags);
                break;
                break;
 
 
/*
/*
 *      Logical condition list (relational operations separated by &&, ||)
 *      Logical condition list (relational operations separated by &&, ||)
 */
 */
        case STATE_COND:
        case STATE_COND:
                state = parseCond(ep, state, flags);
                state = parseCond(ep, state, flags);
                break;
                break;
 
 
/*
/*
 *      Expression list
 *      Expression list
 */
 */
        case STATE_RELEXP:
        case STATE_RELEXP:
                state = parseExpr(ep, state, flags);
                state = parseExpr(ep, state, flags);
                break;
                break;
        }
        }
 
 
        if (state == STATE_ERR && ep->error == NULL) {
        if (state == STATE_ERR && ep->error == NULL) {
                ejError(ep, T("Syntax error"));
                ejError(ep, T("Syntax error"));
        }
        }
        return state;
        return state;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Parse any statement including functions and simple relational operations
 *      Parse any statement including functions and simple relational operations
 */
 */
 
 
static int parseStmt(ej_t *ep, int state, int flags)
static int parseStmt(ej_t *ep, int state, int flags)
{
{
        ejfunc_t        func;
        ejfunc_t        func;
        ejfunc_t        *saveFunc;
        ejfunc_t        *saveFunc;
        ejinput_t       condScript, endScript, bodyScript, incrScript;
        ejinput_t       condScript, endScript, bodyScript, incrScript;
        char_t          *value;
        char_t          *value;
        char_t          *identifier;
        char_t          *identifier;
        int                     done, expectSemi, thenFlags, elseFlags, tid, cond, forFlags;
        int                     done, expectSemi, thenFlags, elseFlags, tid, cond, forFlags;
 
 
        a_assert(ep);
        a_assert(ep);
 
 
/*
/*
 *      Set these to NULL, else we try to free them if an error occurs.
 *      Set these to NULL, else we try to free them if an error occurs.
 */
 */
        endScript.putBackToken = NULL;
        endScript.putBackToken = NULL;
        bodyScript.putBackToken = NULL;
        bodyScript.putBackToken = NULL;
        incrScript.putBackToken = NULL;
        incrScript.putBackToken = NULL;
        condScript.putBackToken = NULL;
        condScript.putBackToken = NULL;
 
 
        expectSemi = 0;
        expectSemi = 0;
        saveFunc = NULL;
        saveFunc = NULL;
 
 
        for (done = 0; !done; ) {
        for (done = 0; !done; ) {
                tid = ejLexGetToken(ep, state);
                tid = ejLexGetToken(ep, state);
 
 
                switch (tid) {
                switch (tid) {
                default:
                default:
                        ejLexPutbackToken(ep, TOK_EXPR, ep->token);
                        ejLexPutbackToken(ep, TOK_EXPR, ep->token);
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_ERR:
                case TOK_ERR:
                        state = STATE_ERR;
                        state = STATE_ERR;
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_EOF:
                case TOK_EOF:
                        state = STATE_EOF;
                        state = STATE_EOF;
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_NEWLINE:
                case TOK_NEWLINE:
                        break;
                        break;
 
 
                case TOK_SEMI:
                case TOK_SEMI:
/*
/*
 *                      This case is when we discover no statement and just a lone ';'
 *                      This case is when we discover no statement and just a lone ';'
 */
 */
                        if (state != STATE_STMT) {
                        if (state != STATE_STMT) {
                                ejLexPutbackToken(ep, tid, ep->token);
                                ejLexPutbackToken(ep, tid, ep->token);
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_ID:
                case TOK_ID:
/*
/*
 *                      This could either be a reference to a variable or an assignment
 *                      This could either be a reference to a variable or an assignment
 */
 */
                        identifier = NULL;
                        identifier = NULL;
                        setString(&identifier, ep->token);
                        setString(&identifier, ep->token);
/*
/*
 *                      Peek ahead to see if this is an assignment
 *                      Peek ahead to see if this is an assignment
 */
 */
                        tid = ejLexGetToken(ep, state);
                        tid = ejLexGetToken(ep, state);
                        if (tid == TOK_ASSIGNMENT) {
                        if (tid == TOK_ASSIGNMENT) {
                                if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
                                if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
                                        goto error;
                                        goto error;
                                }
                                }
                                if (flags & FLAGS_EXE) {
                                if (flags & FLAGS_EXE) {
                                        if ( state == STATE_DEC ) {
                                        if ( state == STATE_DEC ) {
                                                ejSetLocalVar(ep->eid, identifier, ep->result);
                                                ejSetLocalVar(ep->eid, identifier, ep->result);
                                        }
                                        }
                                        else {
                                        else {
                                                if (ejGetVar(ep->eid, identifier, &value) > 0) {
                                                if (ejGetVar(ep->eid, identifier, &value) > 0) {
                                                        ejSetLocalVar(ep->eid, identifier, ep->result);
                                                        ejSetLocalVar(ep->eid, identifier, ep->result);
                                                } else {
                                                } else {
                                                        ejSetGlobalVar(ep->eid, identifier, ep->result);
                                                        ejSetGlobalVar(ep->eid, identifier, ep->result);
                                                }
                                                }
                                        }
                                        }
                                }
                                }
 
 
                        } else if (tid == TOK_INC_DEC ) {
                        } else if (tid == TOK_INC_DEC ) {
                                value = NULL;
                                value = NULL;
                                if ( flags & FLAGS_EXE ) {
                                if ( flags & FLAGS_EXE ) {
                                        if (ejGetVar(ep->eid, identifier, &value) < 0) {
                                        if (ejGetVar(ep->eid, identifier, &value) < 0) {
                                                ejError(ep, T("Undefined variable %s\n"), identifier);
                                                ejError(ep, T("Undefined variable %s\n"), identifier);
                                                goto error;
                                                goto error;
                                        }
                                        }
                                        setString(&ep->result, value);
                                        setString(&ep->result, value);
                                        if (evalExpr(ep, value, (int) *ep->token, T("1")) < 0) {
                                        if (evalExpr(ep, value, (int) *ep->token, T("1")) < 0) {
                                                state = STATE_ERR;
                                                state = STATE_ERR;
                                                break;
                                                break;
                                        }
                                        }
                                        ejSetGlobalVar(ep->eid, identifier, ep->result);
                                        ejSetGlobalVar(ep->eid, identifier, ep->result);
                                }
                                }
 
 
                        } else {
                        } else {
/*
/*
 *                              If we are processing a declaration, allow undefined vars
 *                              If we are processing a declaration, allow undefined vars
 */
 */
                                value = NULL;
                                value = NULL;
                                if (state == STATE_DEC) {
                                if (state == STATE_DEC) {
                                        if (ejGetVar(ep->eid, identifier, &value) > 0) {
                                        if (ejGetVar(ep->eid, identifier, &value) > 0) {
                                                ejError(ep, T("Variable already declared"),
                                                ejError(ep, T("Variable already declared"),
                                                        identifier);
                                                        identifier);
                                                clearString(&identifier);
                                                clearString(&identifier);
                                                goto error;
                                                goto error;
                                        }
                                        }
                                        ejSetLocalVar(ep->eid, identifier, NULL);
                                        ejSetLocalVar(ep->eid, identifier, NULL);
                                } else {
                                } else {
                                        if ( flags & FLAGS_EXE ) {
                                        if ( flags & FLAGS_EXE ) {
                                                if (ejGetVar(ep->eid, identifier, &value) < 0) {
                                                if (ejGetVar(ep->eid, identifier, &value) < 0) {
                                                        ejError(ep, T("Undefined variable %s\n"),
                                                        ejError(ep, T("Undefined variable %s\n"),
                                                                identifier);
                                                                identifier);
                                                        clearString(&identifier);
                                                        clearString(&identifier);
                                                        goto error;
                                                        goto error;
                                                }
                                                }
                                        }
                                        }
                                }
                                }
                                setString(&ep->result, value);
                                setString(&ep->result, value);
                                ejLexPutbackToken(ep, tid, ep->token);
                                ejLexPutbackToken(ep, tid, ep->token);
                        }
                        }
                        clearString(&identifier);
                        clearString(&identifier);
 
 
                        if (state == STATE_STMT) {
                        if (state == STATE_STMT) {
                                expectSemi++;
                                expectSemi++;
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_LITERAL:
                case TOK_LITERAL:
/*
/*
 *                      Set the result to the literal (number or string constant)
 *                      Set the result to the literal (number or string constant)
 */
 */
                        setString(&ep->result, ep->token);
                        setString(&ep->result, ep->token);
                        if (state == STATE_STMT) {
                        if (state == STATE_STMT) {
                                expectSemi++;
                                expectSemi++;
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_FUNCTION:
                case TOK_FUNCTION:
/*
/*
 *                      We must save any current ep->func value for the current stack frame
 *                      We must save any current ep->func value for the current stack frame
 */
 */
                        if (ep->func) {
                        if (ep->func) {
                                saveFunc = ep->func;
                                saveFunc = ep->func;
                        }
                        }
                        memset(&func, 0, sizeof(ejfunc_t));
                        memset(&func, 0, sizeof(ejfunc_t));
                        setString(&func.fname, ep->token);
                        setString(&func.fname, ep->token);
                        ep->func = &func;
                        ep->func = &func;
 
 
                        setString(&ep->result, T(""));
                        setString(&ep->result, T(""));
                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
                                freeFunc(&func);
                                freeFunc(&func);
                                goto error;
                                goto error;
                        }
                        }
 
 
                        if (parse(ep, STATE_ARG_LIST, flags) != STATE_ARG_LIST_DONE) {
                        if (parse(ep, STATE_ARG_LIST, flags) != STATE_ARG_LIST_DONE) {
                                freeFunc(&func);
                                freeFunc(&func);
                                ep->func = saveFunc;
                                ep->func = saveFunc;
                                goto error;
                                goto error;
                        }
                        }
/*
/*
 *                      Evaluate the function if required
 *                      Evaluate the function if required
 */
 */
                        if (flags & FLAGS_EXE && evalFunction(ep) < 0) {
                        if (flags & FLAGS_EXE && evalFunction(ep) < 0) {
                                freeFunc(&func);
                                freeFunc(&func);
                                ep->func = saveFunc;
                                ep->func = saveFunc;
                                goto error;
                                goto error;
                        }
                        }
 
 
                        freeFunc(&func);
                        freeFunc(&func);
                        ep->func = saveFunc;
                        ep->func = saveFunc;
 
 
                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                                goto error;
                                goto error;
                        }
                        }
                        if (state == STATE_STMT) {
                        if (state == STATE_STMT) {
                                expectSemi++;
                                expectSemi++;
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_IF:
                case TOK_IF:
                        if (state != STATE_STMT) {
                        if (state != STATE_STMT) {
                                goto error;
                                goto error;
                        }
                        }
                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
                                goto error;
                                goto error;
                        }
                        }
/*
/*
 *                      Evaluate the entire condition list "(condition)"
 *                      Evaluate the entire condition list "(condition)"
 */
 */
                        if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
                        if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                                goto error;
                                goto error;
                        }
                        }
/*
/*
 *                      This is the "then" case. We need to always parse both cases and
 *                      This is the "then" case. We need to always parse both cases and
 *                      execute only the relevant case.
 *                      execute only the relevant case.
 */
 */
                        if (*ep->result == '1') {
                        if (*ep->result == '1') {
                                thenFlags = flags;
                                thenFlags = flags;
                                elseFlags = flags & ~FLAGS_EXE;
                                elseFlags = flags & ~FLAGS_EXE;
                        } else {
                        } else {
                                thenFlags = flags & ~FLAGS_EXE;
                                thenFlags = flags & ~FLAGS_EXE;
                                elseFlags = flags;
                                elseFlags = flags;
                        }
                        }
/*
/*
 *                      Process the "then" case
 *                      Process the "then" case
 */
 */
                        if (parse(ep, STATE_STMT, thenFlags) != STATE_STMT_DONE) {
                        if (parse(ep, STATE_STMT, thenFlags) != STATE_STMT_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        tid = ejLexGetToken(ep, state);
                        tid = ejLexGetToken(ep, state);
                        if (tid != TOK_ELSE) {
                        if (tid != TOK_ELSE) {
                                ejLexPutbackToken(ep, tid, ep->token);
                                ejLexPutbackToken(ep, tid, ep->token);
                                done++;
                                done++;
                                break;
                                break;
                        }
                        }
/*
/*
 *                      Process the "else" case
 *                      Process the "else" case
 */
 */
                        if (parse(ep, STATE_STMT, elseFlags) != STATE_STMT_DONE) {
                        if (parse(ep, STATE_STMT, elseFlags) != STATE_STMT_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_FOR:
                case TOK_FOR:
/*
/*
 *                      Format for the expression is:
 *                      Format for the expression is:
 *
 *
 *                              for (initial; condition; incr) {
 *                              for (initial; condition; incr) {
 *                                      body;
 *                                      body;
 *                              }
 *                              }
 */
 */
                        if (state != STATE_STMT) {
                        if (state != STATE_STMT) {
                                goto error;
                                goto error;
                        }
                        }
                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
                        if (ejLexGetToken(ep, state) != TOK_LPAREN) {
                                goto error;
                                goto error;
                        }
                        }
 
 
/*
/*
 *                      Evaluate the for loop initialization statement
 *                      Evaluate the for loop initialization statement
 */
 */
                        if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
                        if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        if (ejLexGetToken(ep, state) != TOK_SEMI) {
                        if (ejLexGetToken(ep, state) != TOK_SEMI) {
                                goto error;
                                goto error;
                        }
                        }
 
 
/*
/*
 *                      The first time through, we save the current input context just
 *                      The first time through, we save the current input context just
 *                      to each step: prior to the conditional, the loop increment and the
 *                      to each step: prior to the conditional, the loop increment and the
 *                      loop body.
 *                      loop body.
 */
 */
                        ejLexSaveInputState(ep, &condScript);
                        ejLexSaveInputState(ep, &condScript);
                        if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
                        if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        cond = (*ep->result != '0');
                        cond = (*ep->result != '0');
 
 
                        if (ejLexGetToken(ep, state) != TOK_SEMI) {
                        if (ejLexGetToken(ep, state) != TOK_SEMI) {
                                goto error;
                                goto error;
                        }
                        }
 
 
/*
/*
 *                      Don't execute the loop increment statement or the body first time
 *                      Don't execute the loop increment statement or the body first time
 */
 */
                        forFlags = flags & ~FLAGS_EXE;
                        forFlags = flags & ~FLAGS_EXE;
                        ejLexSaveInputState(ep, &incrScript);
                        ejLexSaveInputState(ep, &incrScript);
                        if (parse(ep, STATE_EXPR, forFlags) != STATE_EXPR_DONE) {
                        if (parse(ep, STATE_EXPR, forFlags) != STATE_EXPR_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                        if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                                goto error;
                                goto error;
                        }
                        }
 
 
/*
/*
 *                      Parse the body and remember the end of the body script
 *                      Parse the body and remember the end of the body script
 */
 */
                        ejLexSaveInputState(ep, &bodyScript);
                        ejLexSaveInputState(ep, &bodyScript);
                        if (parse(ep, STATE_STMT, forFlags) != STATE_STMT_DONE) {
                        if (parse(ep, STATE_STMT, forFlags) != STATE_STMT_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        ejLexSaveInputState(ep, &endScript);
                        ejLexSaveInputState(ep, &endScript);
 
 
/*
/*
 *                      Now actually do the for loop. Note loop has been rotated
 *                      Now actually do the for loop. Note loop has been rotated
 */
 */
                        while (cond && (flags & FLAGS_EXE) ) {
                        while (cond && (flags & FLAGS_EXE) ) {
/*
/*
 *                              Evaluate the body
 *                              Evaluate the body
 */
 */
                                ejLexRestoreInputState(ep, &bodyScript);
                                ejLexRestoreInputState(ep, &bodyScript);
                                if (parse(ep, STATE_STMT, flags) != STATE_STMT_DONE) {
                                if (parse(ep, STATE_STMT, flags) != STATE_STMT_DONE) {
                                        goto error;
                                        goto error;
                                }
                                }
/*
/*
 *                              Evaluate the increment script
 *                              Evaluate the increment script
 */
 */
                                ejLexRestoreInputState(ep, &incrScript);
                                ejLexRestoreInputState(ep, &incrScript);
                                if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
                                if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
                                        goto error;
                                        goto error;
                                }
                                }
/*
/*
 *                              Evaluate the condition
 *                              Evaluate the condition
 */
 */
                                ejLexRestoreInputState(ep, &condScript);
                                ejLexRestoreInputState(ep, &condScript);
                                if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
                                if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
                                        goto error;
                                        goto error;
                                }
                                }
                                cond = (*ep->result != '0');
                                cond = (*ep->result != '0');
                        }
                        }
                        ejLexRestoreInputState(ep, &endScript);
                        ejLexRestoreInputState(ep, &endScript);
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_VAR:
                case TOK_VAR:
                        if (parse(ep, STATE_DEC_LIST, flags) != STATE_DEC_LIST_DONE) {
                        if (parse(ep, STATE_DEC_LIST, flags) != STATE_DEC_LIST_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_COMMA:
                case TOK_COMMA:
                        ejLexPutbackToken(ep, TOK_EXPR, ep->token);
                        ejLexPutbackToken(ep, TOK_EXPR, ep->token);
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_LPAREN:
                case TOK_LPAREN:
                        if (state == STATE_EXPR) {
                        if (state == STATE_EXPR) {
                                if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
                                if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
                                        goto error;
                                        goto error;
                                }
                                }
                                if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                                if (ejLexGetToken(ep, state) != TOK_RPAREN) {
                                        goto error;
                                        goto error;
                                }
                                }
                                return STATE_EXPR_DONE;
                                return STATE_EXPR_DONE;
                        }
                        }
                        done++;
                        done++;
                        break;
                        break;
 
 
                case TOK_RPAREN:
                case TOK_RPAREN:
                        ejLexPutbackToken(ep, tid, ep->token);
                        ejLexPutbackToken(ep, tid, ep->token);
                        return STATE_EXPR_DONE;
                        return STATE_EXPR_DONE;
 
 
                case TOK_LBRACE:
                case TOK_LBRACE:
/*
/*
 *                      This handles any code in braces except "if () {} else {}"
 *                      This handles any code in braces except "if () {} else {}"
 */
 */
                        if (state != STATE_STMT) {
                        if (state != STATE_STMT) {
                                goto error;
                                goto error;
                        }
                        }
 
 
/*
/*
 *                      Parse will return STATE_STMT_BLOCK_DONE when the RBRACE is seen
 *                      Parse will return STATE_STMT_BLOCK_DONE when the RBRACE is seen
 */
 */
                        do {
                        do {
                                state = parse(ep, STATE_STMT, flags);
                                state = parse(ep, STATE_STMT, flags);
                        } while (state == STATE_STMT_DONE);
                        } while (state == STATE_STMT_DONE);
 
 
                        if (ejLexGetToken(ep, state) != TOK_RBRACE) {
                        if (ejLexGetToken(ep, state) != TOK_RBRACE) {
                                goto error;
                                goto error;
                        }
                        }
                        return STATE_STMT_DONE;
                        return STATE_STMT_DONE;
 
 
                case TOK_RBRACE:
                case TOK_RBRACE:
                        if (state == STATE_STMT) {
                        if (state == STATE_STMT) {
                                ejLexPutbackToken(ep, tid, ep->token);
                                ejLexPutbackToken(ep, tid, ep->token);
                                return STATE_STMT_BLOCK_DONE;
                                return STATE_STMT_BLOCK_DONE;
                        }
                        }
                        goto error;
                        goto error;
 
 
                case TOK_RETURN:
                case TOK_RETURN:
                        if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
                        if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
                                goto error;
                                goto error;
                        }
                        }
                        if (flags & FLAGS_EXE) {
                        if (flags & FLAGS_EXE) {
                                while ( ejLexGetToken(ep, state) != TOK_EOF );
                                while ( ejLexGetToken(ep, state) != TOK_EOF );
                                done++;
                                done++;
                                return STATE_EOF;
                                return STATE_EOF;
                        }
                        }
                        break;
                        break;
                }
                }
        }
        }
 
 
        if (expectSemi) {
        if (expectSemi) {
                tid = ejLexGetToken(ep, state);
                tid = ejLexGetToken(ep, state);
                if (tid != TOK_SEMI && tid != TOK_NEWLINE) {
                if (tid != TOK_SEMI && tid != TOK_NEWLINE) {
                        goto error;
                        goto error;
                }
                }
 
 
/*
/*
 *              Skip newline after semi-colon
 *              Skip newline after semi-colon
 */
 */
                tid = ejLexGetToken(ep, state);
                tid = ejLexGetToken(ep, state);
                if (tid != TOK_NEWLINE) {
                if (tid != TOK_NEWLINE) {
                        ejLexPutbackToken(ep, tid, ep->token);
                        ejLexPutbackToken(ep, tid, ep->token);
                }
                }
        }
        }
 
 
/*
/*
 *      Free resources and return the correct status
 *      Free resources and return the correct status
 */
 */
doneParse:
doneParse:
        if (tid == TOK_FOR) {
        if (tid == TOK_FOR) {
                ejLexFreeInputState(ep, &condScript);
                ejLexFreeInputState(ep, &condScript);
                ejLexFreeInputState(ep, &incrScript);
                ejLexFreeInputState(ep, &incrScript);
                ejLexFreeInputState(ep, &endScript);
                ejLexFreeInputState(ep, &endScript);
                ejLexFreeInputState(ep, &bodyScript);
                ejLexFreeInputState(ep, &bodyScript);
        }
        }
        if (state == STATE_STMT) {
        if (state == STATE_STMT) {
                return STATE_STMT_DONE;
                return STATE_STMT_DONE;
        } else if (state == STATE_DEC) {
        } else if (state == STATE_DEC) {
                return STATE_DEC_DONE;
                return STATE_DEC_DONE;
        } else if (state == STATE_EXPR) {
        } else if (state == STATE_EXPR) {
                return STATE_EXPR_DONE;
                return STATE_EXPR_DONE;
        } else if (state == STATE_EOF) {
        } else if (state == STATE_EOF) {
                return state;
                return state;
        } else {
        } else {
                return STATE_ERR;
                return STATE_ERR;
        }
        }
 
 
/*
/*
 *      Common error exit
 *      Common error exit
 */
 */
error:
error:
        state = STATE_ERR;
        state = STATE_ERR;
        goto doneParse;
        goto doneParse;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Parse variable declaration list
 *      Parse variable declaration list
 */
 */
 
 
static int parseDeclaration(ej_t *ep, int state, int flags)
static int parseDeclaration(ej_t *ep, int state, int flags)
{
{
        int             tid;
        int             tid;
 
 
        a_assert(ep);
        a_assert(ep);
 
 
/*
/*
 *      Declarations can be of the following forms:
 *      Declarations can be of the following forms:
 *                      var x;
 *                      var x;
 *                      var x, y, z;
 *                      var x, y, z;
 *                      var x = 1 + 2 / 3, y = 2 + 4;
 *                      var x = 1 + 2 / 3, y = 2 + 4;
 *
 *
 *      We set the variable to NULL if there is no associated assignment.
 *      We set the variable to NULL if there is no associated assignment.
 */
 */
 
 
        do {
        do {
                if ((tid = ejLexGetToken(ep, state)) != TOK_ID) {
                if ((tid = ejLexGetToken(ep, state)) != TOK_ID) {
                        return STATE_ERR;
                        return STATE_ERR;
                }
                }
                ejLexPutbackToken(ep, tid, ep->token);
                ejLexPutbackToken(ep, tid, ep->token);
 
 
/*
/*
 *              Parse the entire assignment or simple identifier declaration
 *              Parse the entire assignment or simple identifier declaration
 */
 */
                if (parse(ep, STATE_DEC, flags) != STATE_DEC_DONE) {
                if (parse(ep, STATE_DEC, flags) != STATE_DEC_DONE) {
                        return STATE_ERR;
                        return STATE_ERR;
                }
                }
 
 
/*
/*
 *              Peek at the next token, continue if comma seen
 *              Peek at the next token, continue if comma seen
 */
 */
                tid = ejLexGetToken(ep, state);
                tid = ejLexGetToken(ep, state);
                if (tid == TOK_SEMI) {
                if (tid == TOK_SEMI) {
                        return STATE_DEC_LIST_DONE;
                        return STATE_DEC_LIST_DONE;
                } else if (tid != TOK_COMMA) {
                } else if (tid != TOK_COMMA) {
                        return STATE_ERR;
                        return STATE_ERR;
                }
                }
        } while (tid == TOK_COMMA);
        } while (tid == TOK_COMMA);
 
 
        if (tid != TOK_SEMI) {
        if (tid != TOK_SEMI) {
                return STATE_ERR;
                return STATE_ERR;
        }
        }
        return STATE_DEC_LIST_DONE;
        return STATE_DEC_LIST_DONE;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Parse function arguments
 *      Parse function arguments
 */
 */
 
 
static int parseArgs(ej_t *ep, int state, int flags)
static int parseArgs(ej_t *ep, int state, int flags)
{
{
        int             tid, aid;
        int             tid, aid;
 
 
        a_assert(ep);
        a_assert(ep);
 
 
        do {
        do {
                state = parse(ep, STATE_RELEXP, flags);
                state = parse(ep, STATE_RELEXP, flags);
                if (state == STATE_EOF || state == STATE_ERR) {
                if (state == STATE_EOF || state == STATE_ERR) {
                        return state;
                        return state;
                }
                }
                if (state == STATE_RELEXP_DONE) {
                if (state == STATE_RELEXP_DONE) {
                        aid = hAlloc((void***) &ep->func->args);
                        aid = hAlloc((void***) &ep->func->args);
                        ep->func->args[aid] = bstrdup(B_L, ep->result);
                        ep->func->args[aid] = bstrdup(B_L, ep->result);
                        ep->func->nArgs++;
                        ep->func->nArgs++;
                }
                }
/*
/*
 *              Peek at the next token, continue if more args (ie. comma seen)
 *              Peek at the next token, continue if more args (ie. comma seen)
 */
 */
                tid = ejLexGetToken(ep, state);
                tid = ejLexGetToken(ep, state);
                if (tid != TOK_COMMA) {
                if (tid != TOK_COMMA) {
                        ejLexPutbackToken(ep, tid, ep->token);
                        ejLexPutbackToken(ep, tid, ep->token);
                }
                }
        } while (tid == TOK_COMMA);
        } while (tid == TOK_COMMA);
 
 
        if (tid != TOK_RPAREN && state != STATE_RELEXP_DONE) {
        if (tid != TOK_RPAREN && state != STATE_RELEXP_DONE) {
                return STATE_ERR;
                return STATE_ERR;
        }
        }
        return STATE_ARG_LIST_DONE;
        return STATE_ARG_LIST_DONE;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Parse conditional expression (relational ops separated by ||, &&)
 *      Parse conditional expression (relational ops separated by ||, &&)
 */
 */
 
 
static int parseCond(ej_t *ep, int state, int flags)
static int parseCond(ej_t *ep, int state, int flags)
{
{
        char_t  *lhs, *rhs;
        char_t  *lhs, *rhs;
        int             tid, operator;
        int             tid, operator;
 
 
        a_assert(ep);
        a_assert(ep);
 
 
        setString(&ep->result, T(""));
        setString(&ep->result, T(""));
        rhs = lhs = NULL;
        rhs = lhs = NULL;
        operator = 0;
        operator = 0;
 
 
        do {
        do {
/*
/*
 *      Recurse to handle one side of a conditional. Accumulate the
 *      Recurse to handle one side of a conditional. Accumulate the
 *      left hand side and the final result in ep->result.
 *      left hand side and the final result in ep->result.
 */
 */
                state = parse(ep, STATE_RELEXP, flags);
                state = parse(ep, STATE_RELEXP, flags);
                if (state != STATE_RELEXP_DONE) {
                if (state != STATE_RELEXP_DONE) {
                        state = STATE_ERR;
                        state = STATE_ERR;
                        break;
                        break;
                }
                }
                if (operator > 0) {
                if (operator > 0) {
                        setString(&rhs, ep->result);
                        setString(&rhs, ep->result);
                        if (evalCond(ep, lhs, operator, rhs) < 0) {
                        if (evalCond(ep, lhs, operator, rhs) < 0) {
                                state = STATE_ERR;
                                state = STATE_ERR;
                                break;
                                break;
                        }
                        }
                }
                }
                setString(&lhs, ep->result);
                setString(&lhs, ep->result);
 
 
                tid = ejLexGetToken(ep, state);
                tid = ejLexGetToken(ep, state);
                if (tid == TOK_LOGICAL) {
                if (tid == TOK_LOGICAL) {
                        operator = (int) *ep->token;
                        operator = (int) *ep->token;
 
 
                } else if (tid == TOK_RPAREN || tid == TOK_SEMI) {
                } else if (tid == TOK_RPAREN || tid == TOK_SEMI) {
                        ejLexPutbackToken(ep, tid, ep->token);
                        ejLexPutbackToken(ep, tid, ep->token);
                        state = STATE_COND_DONE;
                        state = STATE_COND_DONE;
                        break;
                        break;
 
 
                } else {
                } else {
                        ejLexPutbackToken(ep, tid, ep->token);
                        ejLexPutbackToken(ep, tid, ep->token);
                }
                }
 
 
        } while (state == STATE_RELEXP_DONE);
        } while (state == STATE_RELEXP_DONE);
 
 
        if (lhs) {
        if (lhs) {
                bfree(B_L, lhs);
                bfree(B_L, lhs);
        }
        }
        if (rhs) {
        if (rhs) {
                bfree(B_L, rhs);
                bfree(B_L, rhs);
        }
        }
        return state;
        return state;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Parse expression (leftHandSide operator rightHandSide)
 *      Parse expression (leftHandSide operator rightHandSide)
 */
 */
 
 
static int parseExpr(ej_t *ep, int state, int flags)
static int parseExpr(ej_t *ep, int state, int flags)
{
{
        char_t  *lhs, *rhs;
        char_t  *lhs, *rhs;
        int             rel, tid;
        int             rel, tid;
 
 
        a_assert(ep);
        a_assert(ep);
 
 
        setString(&ep->result, T(""));
        setString(&ep->result, T(""));
        rhs = lhs = NULL;
        rhs = lhs = NULL;
        rel = 0;
        rel = 0;
 
 
        do {
        do {
/*
/*
 *      This loop will handle an entire expression list. We call parse
 *      This loop will handle an entire expression list. We call parse
 *      to evalutate each term which returns the result in ep->result.
 *      to evalutate each term which returns the result in ep->result.
 */
 */
                state = parse(ep, STATE_EXPR, flags);
                state = parse(ep, STATE_EXPR, flags);
                if (state != STATE_EXPR_DONE) {
                if (state != STATE_EXPR_DONE) {
                        state = STATE_ERR;
                        state = STATE_ERR;
                        break;
                        break;
                }
                }
                if (rel > 0) {
                if (rel > 0) {
                        setString(&rhs, ep->result);
                        setString(&rhs, ep->result);
                        if (evalExpr(ep, lhs, rel, rhs) < 0) {
                        if (evalExpr(ep, lhs, rel, rhs) < 0) {
                                state = STATE_ERR;
                                state = STATE_ERR;
                                break;
                                break;
                        }
                        }
                }
                }
                setString(&lhs, ep->result);
                setString(&lhs, ep->result);
 
 
                if ((tid = ejLexGetToken(ep, state)) == TOK_EXPR) {
                if ((tid = ejLexGetToken(ep, state)) == TOK_EXPR) {
                        rel = (int) *ep->token;
                        rel = (int) *ep->token;
 
 
                } else if (tid == TOK_INC_DEC) {
                } else if (tid == TOK_INC_DEC) {
                        rel = (int) *ep->token;
                        rel = (int) *ep->token;
 
 
                } else {
                } else {
                        ejLexPutbackToken(ep, tid, ep->token);
                        ejLexPutbackToken(ep, tid, ep->token);
                        state = STATE_RELEXP_DONE;
                        state = STATE_RELEXP_DONE;
                }
                }
 
 
        } while (state == STATE_EXPR_DONE);
        } while (state == STATE_EXPR_DONE);
 
 
        if (rhs)
        if (rhs)
                bfree(B_L, rhs);
                bfree(B_L, rhs);
        if (lhs)
        if (lhs)
                bfree(B_L, lhs);
                bfree(B_L, lhs);
        return state;
        return state;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Evaluate a condition. Implements &&, ||, !
 *      Evaluate a condition. Implements &&, ||, !
 */
 */
 
 
static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
{
{
        char_t  buf[16];
        char_t  buf[16];
        int             l, r, lval;
        int             l, r, lval;
 
 
        a_assert(lhs);
        a_assert(lhs);
        a_assert(rhs);
        a_assert(rhs);
        a_assert(rel > 0);
        a_assert(rel > 0);
 
 
        lval = 0;
        lval = 0;
        if (gisdigit(*lhs) && gisdigit(*rhs)) {
        if (gisdigit(*lhs) && gisdigit(*rhs)) {
                l = gatoi(lhs);
                l = gatoi(lhs);
                r = gatoi(rhs);
                r = gatoi(rhs);
                switch (rel) {
                switch (rel) {
                case COND_AND:
                case COND_AND:
                        lval = l && r;
                        lval = l && r;
                        break;
                        break;
                case COND_OR:
                case COND_OR:
                        lval = l || r;
                        lval = l || r;
                        break;
                        break;
                default:
                default:
                        ejError(ep, T("Bad operator %d"), rel);
                        ejError(ep, T("Bad operator %d"), rel);
                        return -1;
                        return -1;
                }
                }
        } else {
        } else {
                if (!gisdigit(*lhs)) {
                if (!gisdigit(*lhs)) {
                        ejError(ep, T("Conditional must be numeric"), lhs);
                        ejError(ep, T("Conditional must be numeric"), lhs);
                } else {
                } else {
                        ejError(ep, T("Conditional must be numeric"), rhs);
                        ejError(ep, T("Conditional must be numeric"), rhs);
                }
                }
        }
        }
 
 
        stritoa(lval, buf, sizeof(buf));
        stritoa(lval, buf, sizeof(buf));
        setString(&ep->result, buf);
        setString(&ep->result, buf);
        return 0;
        return 0;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Evaluate an operation
 *      Evaluate an operation
 */
 */
 
 
static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
{
{
        char_t  *cp, buf[16];
        char_t  *cp, buf[16];
        int             numeric, l, r, lval;
        int             numeric, l, r, lval;
 
 
        a_assert(lhs);
        a_assert(lhs);
        a_assert(rhs);
        a_assert(rhs);
        a_assert(rel > 0);
        a_assert(rel > 0);
 
 
/*
/*
 *      All of the characters in the lhs and rhs must be numeric
 *      All of the characters in the lhs and rhs must be numeric
 */
 */
        numeric = 1;
        numeric = 1;
        for (cp = lhs; *cp; cp++) {
        for (cp = lhs; *cp; cp++) {
                if (!gisdigit(*cp)) {
                if (!gisdigit(*cp)) {
                        numeric = 0;
                        numeric = 0;
                        break;
                        break;
                }
                }
        }
        }
        if (numeric) {
        if (numeric) {
                for (cp = rhs; *cp; cp++) {
                for (cp = rhs; *cp; cp++) {
                        if (!gisdigit(*cp)) {
                        if (!gisdigit(*cp)) {
                                numeric = 0;
                                numeric = 0;
                                break;
                                break;
                        }
                        }
                }
                }
        }
        }
        if (numeric) {
        if (numeric) {
                l = gatoi(lhs);
                l = gatoi(lhs);
                r = gatoi(rhs);
                r = gatoi(rhs);
                switch (rel) {
                switch (rel) {
                case EXPR_PLUS:
                case EXPR_PLUS:
                        lval = l + r;
                        lval = l + r;
                        break;
                        break;
                case EXPR_INC:
                case EXPR_INC:
                        lval = l + 1;
                        lval = l + 1;
                        break;
                        break;
                case EXPR_MINUS:
                case EXPR_MINUS:
                        lval = l - r;
                        lval = l - r;
                        break;
                        break;
                case EXPR_DEC:
                case EXPR_DEC:
                        lval = l - 1;
                        lval = l - 1;
                        break;
                        break;
                case EXPR_MUL:
                case EXPR_MUL:
                        lval = l * r;
                        lval = l * r;
                        break;
                        break;
                case EXPR_DIV:
                case EXPR_DIV:
                        if (r != 0) {
                        if (r != 0) {
                                lval = l / r;
                                lval = l / r;
                        } else {
                        } else {
                                lval = 0;
                                lval = 0;
                        }
                        }
                        break;
                        break;
                case EXPR_MOD:
                case EXPR_MOD:
                        if (r != 0) {
                        if (r != 0) {
                                lval = l % r;
                                lval = l % r;
                        } else {
                        } else {
                                lval = 0;
                                lval = 0;
                        }
                        }
                        break;
                        break;
                case EXPR_LSHIFT:
                case EXPR_LSHIFT:
                        lval = l << r;
                        lval = l << r;
                        break;
                        break;
                case EXPR_RSHIFT:
                case EXPR_RSHIFT:
                        lval = l >> r;
                        lval = l >> r;
                        break;
                        break;
                case EXPR_EQ:
                case EXPR_EQ:
                        lval = l == r;
                        lval = l == r;
                        break;
                        break;
                case EXPR_NOTEQ:
                case EXPR_NOTEQ:
                        lval = l != r;
                        lval = l != r;
                        break;
                        break;
                case EXPR_LESS:
                case EXPR_LESS:
                        lval = (l < r) ? 1 : 0;
                        lval = (l < r) ? 1 : 0;
                        break;
                        break;
                case EXPR_LESSEQ:
                case EXPR_LESSEQ:
                        lval = (l <= r) ? 1 : 0;
                        lval = (l <= r) ? 1 : 0;
                        break;
                        break;
                case EXPR_GREATER:
                case EXPR_GREATER:
                        lval = (l > r) ? 1 : 0;
                        lval = (l > r) ? 1 : 0;
                        break;
                        break;
                case EXPR_GREATEREQ:
                case EXPR_GREATEREQ:
                        lval = (l >= r) ? 1 : 0;
                        lval = (l >= r) ? 1 : 0;
                        break;
                        break;
                default:
                default:
                        ejError(ep, T("Bad operator %d"), rel);
                        ejError(ep, T("Bad operator %d"), rel);
                        return -1;
                        return -1;
                }
                }
 
 
        } else {
        } else {
                switch (rel) {
                switch (rel) {
                case EXPR_PLUS:
                case EXPR_PLUS:
                        clearString(&ep->result);
                        clearString(&ep->result);
                        appendString(&ep->result, lhs);
                        appendString(&ep->result, lhs);
                        appendString(&ep->result, rhs);
                        appendString(&ep->result, rhs);
                        return 0;
                        return 0;
                case EXPR_LESS:
                case EXPR_LESS:
                        lval = gstrcmp(lhs, rhs) < 0;
                        lval = gstrcmp(lhs, rhs) < 0;
                        break;
                        break;
                case EXPR_LESSEQ:
                case EXPR_LESSEQ:
                        lval = gstrcmp(lhs, rhs) <= 0;
                        lval = gstrcmp(lhs, rhs) <= 0;
                        break;
                        break;
                case EXPR_GREATER:
                case EXPR_GREATER:
                        lval = gstrcmp(lhs, rhs) > 0;
                        lval = gstrcmp(lhs, rhs) > 0;
                        break;
                        break;
                case EXPR_GREATEREQ:
                case EXPR_GREATEREQ:
                        lval = gstrcmp(lhs, rhs) >= 0;
                        lval = gstrcmp(lhs, rhs) >= 0;
                        break;
                        break;
                case EXPR_EQ:
                case EXPR_EQ:
                        lval = gstrcmp(lhs, rhs) == 0;
                        lval = gstrcmp(lhs, rhs) == 0;
                        break;
                        break;
                case EXPR_NOTEQ:
                case EXPR_NOTEQ:
                        lval = gstrcmp(lhs, rhs) != 0;
                        lval = gstrcmp(lhs, rhs) != 0;
                        break;
                        break;
                case EXPR_INC:
                case EXPR_INC:
                case EXPR_DEC:
                case EXPR_DEC:
                case EXPR_MINUS:
                case EXPR_MINUS:
                case EXPR_DIV:
                case EXPR_DIV:
                case EXPR_MOD:
                case EXPR_MOD:
                case EXPR_LSHIFT:
                case EXPR_LSHIFT:
                case EXPR_RSHIFT:
                case EXPR_RSHIFT:
                default:
                default:
                        ejError(ep, T("Bad operator"));
                        ejError(ep, T("Bad operator"));
                        return -1;
                        return -1;
                }
                }
        }
        }
 
 
        stritoa(lval, buf, sizeof(buf));
        stritoa(lval, buf, sizeof(buf));
        setString(&ep->result, buf);
        setString(&ep->result, buf);
        return 0;
        return 0;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Evaluate a function
 *      Evaluate a function
 */
 */
 
 
static int evalFunction(ej_t *ep)
static int evalFunction(ej_t *ep)
{
{
        sym_t   *sp;
        sym_t   *sp;
        int             (*fn)(int eid, void *handle, int argc, char_t **argv);
        int             (*fn)(int eid, void *handle, int argc, char_t **argv);
 
 
        if ((sp = symLookup(ep->functions, ep->func->fname)) == NULL) {
        if ((sp = symLookup(ep->functions, ep->func->fname)) == NULL) {
                ejError(ep, T("Undefined procedure %s"), ep->func->fname);
                ejError(ep, T("Undefined procedure %s"), ep->func->fname);
                return -1;
                return -1;
        }
        }
        fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer;
        fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer;
        if (fn == NULL) {
        if (fn == NULL) {
                ejError(ep, T("Undefined procedure %s"), ep->func->fname);
                ejError(ep, T("Undefined procedure %s"), ep->func->fname);
                return -1;
                return -1;
        }
        }
 
 
        return (*fn)(ep->eid, (void*) ep->userHandle, ep->func->nArgs,
        return (*fn)(ep->eid, (void*) ep->userHandle, ep->func->nArgs,
                ep->func->args);
                ep->func->args);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Output a parse ej_error message
 *      Output a parse ej_error message
 */
 */
 
 
void ejError(ej_t* ep, char_t* fmt, ...)
void ejError(ej_t* ep, char_t* fmt, ...)
{
{
        va_list         args;
        va_list         args;
        ejinput_t       *ip;
        ejinput_t       *ip;
        char_t          *errbuf, *msgbuf;
        char_t          *errbuf, *msgbuf;
 
 
        a_assert(ep);
        a_assert(ep);
        a_assert(fmt);
        a_assert(fmt);
        ip = ep->input;
        ip = ep->input;
 
 
        va_start(args, fmt);
        va_start(args, fmt);
        msgbuf = NULL;
        msgbuf = NULL;
        gvsnprintf(&msgbuf, E_MAX_ERROR, fmt, args);
        gvsnprintf(&msgbuf, E_MAX_ERROR, fmt, args);
        va_end(args);
        va_end(args);
 
 
        if (ep && ip) {
        if (ep && ip) {
                errbuf = NULL;
                errbuf = NULL;
                gsnprintf(&errbuf, E_MAX_ERROR, T("%s\n At line %d, line => \n\n%s\n"),
                gsnprintf(&errbuf, E_MAX_ERROR, T("%s\n At line %d, line => \n\n%s\n"),
                        msgbuf, ip->lineNumber, ip->line);
                        msgbuf, ip->lineNumber, ip->line);
                bfreeSafe(B_L, ep->error);
                bfreeSafe(B_L, ep->error);
                ep->error = errbuf;
                ep->error = errbuf;
        }
        }
        bfreeSafe(B_L, msgbuf);
        bfreeSafe(B_L, msgbuf);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Clear a string value
 *      Clear a string value
 */
 */
 
 
static void clearString(char_t **ptr)
static void clearString(char_t **ptr)
{
{
        a_assert(ptr);
        a_assert(ptr);
 
 
        if (*ptr) {
        if (*ptr) {
                bfree(B_L, *ptr);
                bfree(B_L, *ptr);
        }
        }
        *ptr = NULL;
        *ptr = NULL;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Set a string value
 *      Set a string value
 */
 */
 
 
static void setString(char_t **ptr, char_t *s)
static void setString(char_t **ptr, char_t *s)
{
{
        a_assert(ptr);
        a_assert(ptr);
 
 
        if (*ptr) {
        if (*ptr) {
                bfree(B_L, *ptr);
                bfree(B_L, *ptr);
        }
        }
        *ptr = bstrdup(B_L, s);
        *ptr = bstrdup(B_L, s);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Append to the pointer value
 *      Append to the pointer value
 */
 */
 
 
static void appendString(char_t **ptr, char_t *s)
static void appendString(char_t **ptr, char_t *s)
{
{
        int     len, oldlen;
        int     len, oldlen;
 
 
        a_assert(ptr);
        a_assert(ptr);
 
 
        if (*ptr) {
        if (*ptr) {
                len = gstrlen(s);
                len = gstrlen(s);
                oldlen = gstrlen(*ptr);
                oldlen = gstrlen(*ptr);
                *ptr = brealloc(B_L, *ptr, (len + oldlen + 1) * sizeof(char_t));
                *ptr = brealloc(B_L, *ptr, (len + oldlen + 1) * sizeof(char_t));
                gstrcpy(&(*ptr)[oldlen], s);
                gstrcpy(&(*ptr)[oldlen], s);
        } else {
        } else {
                *ptr = bstrdup(B_L, s);
                *ptr = bstrdup(B_L, s);
        }
        }
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Define a function
 *      Define a function
 */
 */
 
 
int ejSetGlobalFunction(int eid, char_t *name,
int ejSetGlobalFunction(int eid, char_t *name,
        int (*fn)(int eid, void *handle, int argc, char_t **argv))
        int (*fn)(int eid, void *handle, int argc, char_t **argv))
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        return ejSetGlobalFunctionDirect(ep->functions, name, fn);
        return ejSetGlobalFunctionDirect(ep->functions, name, fn);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Define a function directly into the function symbol table.
 *      Define a function directly into the function symbol table.
 */
 */
 
 
int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name,
int ejSetGlobalFunctionDirect(sym_fd_t functions, char_t *name,
        int (*fn)(int eid, void *handle, int argc, char_t **argv))
        int (*fn)(int eid, void *handle, int argc, char_t **argv))
{
{
        if (symEnter(functions, name, valueInteger((long) fn), 0) == NULL) {
        if (symEnter(functions, name, valueInteger((long) fn), 0) == NULL) {
                return -1;
                return -1;
        }
        }
        return 0;
        return 0;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get a function definition
 *      Get a function definition
 */
 */
 
 
void *ejGetGlobalFunction(int eid, char_t *name)
void *ejGetGlobalFunction(int eid, char_t *name)
{
{
        ej_t    *ep;
        ej_t    *ep;
        sym_t   *sp;
        sym_t   *sp;
        int             (*fn)(int eid, void *handle, int argc, char_t **argv);
        int             (*fn)(int eid, void *handle, int argc, char_t **argv);
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return NULL;
                return NULL;
        }
        }
        if ((sp = symLookup(ep->functions, name)) != NULL) {
        if ((sp = symLookup(ep->functions, name)) != NULL) {
                fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer;
                fn = (int (*)(int, void*, int, char_t**)) sp->content.value.integer;
                return (void*) fn;
                return (void*) fn;
        }
        }
        return NULL;
        return NULL;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Utility routine to crack Ejscript arguments. Return the number of args
 *      Utility routine to crack Ejscript arguments. Return the number of args
 *      seen. This routine only supports %s and %d type args.
 *      seen. This routine only supports %s and %d type args.
 *
 *
 *      Typical usage:
 *      Typical usage:
 *
 *
 *              if (ejArgs(argc, argv, "%s %d", &name, &age) < 2) {
 *              if (ejArgs(argc, argv, "%s %d", &name, &age) < 2) {
 *                      error("Insufficient args\n");
 *                      error("Insufficient args\n");
 *                      return -1;
 *                      return -1;
 *              }
 *              }
 */
 */
 
 
int ejArgs(int argc, char_t **argv, char_t *fmt, ...)
int ejArgs(int argc, char_t **argv, char_t *fmt, ...)
{
{
        va_list vargs;
        va_list vargs;
        char_t  *cp, **sp;
        char_t  *cp, **sp;
        int             *ip;
        int             *ip;
        int             argn;
        int             argn;
 
 
        va_start(vargs, fmt);
        va_start(vargs, fmt);
 
 
        if (argv == NULL) {
        if (argv == NULL) {
                return 0;
                return 0;
        }
        }
 
 
        for (argn = 0, cp = fmt; cp && *cp && argv[argn]; ) {
        for (argn = 0, cp = fmt; cp && *cp && argv[argn]; ) {
                if (*cp++ != '%') {
                if (*cp++ != '%') {
                        continue;
                        continue;
                }
                }
 
 
                switch (*cp) {
                switch (*cp) {
                case 'd':
                case 'd':
                        ip = va_arg(vargs, int*);
                        ip = va_arg(vargs, int*);
                        *ip = gatoi(argv[argn]);
                        *ip = gatoi(argv[argn]);
                        break;
                        break;
 
 
                case 's':
                case 's':
                        sp = va_arg(vargs, char_t**);
                        sp = va_arg(vargs, char_t**);
                        *sp = argv[argn];
                        *sp = argv[argn];
                        break;
                        break;
 
 
                default:
                default:
/*
/*
 *                      Unsupported
 *                      Unsupported
 */
 */
                        a_assert(0);
                        a_assert(0);
                }
                }
                argn++;
                argn++;
        }
        }
 
 
        va_end(vargs);
        va_end(vargs);
        return argn;
        return argn;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Define the user handle
 *      Define the user handle
 */
 */
 
 
void ejSetUserHandle(int eid, int handle)
void ejSetUserHandle(int eid, int handle)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return;
                return;
        }
        }
        ep->userHandle = handle;
        ep->userHandle = handle;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get the user handle
 *      Get the user handle
 */
 */
 
 
int ejGetUserHandle(int eid)
int ejGetUserHandle(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        return ep->userHandle;
        return ep->userHandle;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get the current line number
 *      Get the current line number
 */
 */
 
 
int ejGetLineNumber(int eid)
int ejGetLineNumber(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        return ep->input->lineNumber;
        return ep->input->lineNumber;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Set the result
 *      Set the result
 */
 */
 
 
void ejSetResult(int eid, char_t *s)
void ejSetResult(int eid, char_t *s)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return;
                return;
        }
        }
        setString(&ep->result, s);
        setString(&ep->result, s);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get the result
 *      Get the result
 */
 */
 
 
char_t *ejGetResult(int eid)
char_t *ejGetResult(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return NULL;
                return NULL;
        }
        }
        return ep->result;
        return ep->result;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Set a variable. Note: a variable with a value of NULL means declared but
 *      Set a variable. Note: a variable with a value of NULL means declared but
 *      undefined. The value is defined in the top-most variable frame.
 *      undefined. The value is defined in the top-most variable frame.
 */
 */
 
 
void ejSetVar(int eid, char_t *var, char_t *value)
void ejSetVar(int eid, char_t *var, char_t *value)
{
{
        ej_t    *ep;
        ej_t    *ep;
        value_t v;
        value_t v;
 
 
        a_assert(var && *var);
        a_assert(var && *var);
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return;
                return;
        }
        }
        if (value == NULL) {
        if (value == NULL) {
                v = valueString(value, 0);
                v = valueString(value, 0);
        } else {
        } else {
                v = valueString(value, VALUE_ALLOCATE);
                v = valueString(value, VALUE_ALLOCATE);
        }
        }
        symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0);
        symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Set a local variable. Note: a variable with a value of NULL means
 *      Set a local variable. Note: a variable with a value of NULL means
 *      declared but undefined. The value is defined in the top-most variable frame.
 *      declared but undefined. The value is defined in the top-most variable frame.
 */
 */
 
 
void ejSetLocalVar(int eid, char_t *var, char_t *value)
void ejSetLocalVar(int eid, char_t *var, char_t *value)
{
{
        ej_t    *ep;
        ej_t    *ep;
        value_t v;
        value_t v;
 
 
        a_assert(var && *var);
        a_assert(var && *var);
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return;
                return;
        }
        }
        if (value == NULL) {
        if (value == NULL) {
                v = valueString(value, 0);
                v = valueString(value, 0);
        } else {
        } else {
                v = valueString(value, VALUE_ALLOCATE);
                v = valueString(value, VALUE_ALLOCATE);
        }
        }
        symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0);
        symEnter(ep->variables[ep->variableMax - 1] - EJ_OFFSET, var, v, 0);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Set a global variable. Note: a variable with a value of NULL means
 *      Set a global variable. Note: a variable with a value of NULL means
 *      declared but undefined. The value is defined in the global variable frame.
 *      declared but undefined. The value is defined in the global variable frame.
 */
 */
 
 
void ejSetGlobalVar(int eid, char_t *var, char_t *value)
void ejSetGlobalVar(int eid, char_t *var, char_t *value)
{
{
        ej_t    *ep;
        ej_t    *ep;
        value_t v;
        value_t v;
 
 
        a_assert(var && *var);
        a_assert(var && *var);
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return;
                return;
        }
        }
        if (value == NULL) {
        if (value == NULL) {
                v = valueString(value, 0);
                v = valueString(value, 0);
        } else {
        } else {
                v = valueString(value, VALUE_ALLOCATE);
                v = valueString(value, VALUE_ALLOCATE);
        }
        }
        symEnter(ep->variables[0] - EJ_OFFSET, var, v, 0);
        symEnter(ep->variables[0] - EJ_OFFSET, var, v, 0);
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get a variable
 *      Get a variable
 */
 */
 
 
int ejGetVar(int eid, char_t *var, char_t **value)
int ejGetVar(int eid, char_t *var, char_t **value)
{
{
        ej_t    *ep;
        ej_t    *ep;
        sym_t   *sp;
        sym_t   *sp;
        int             i;
        int             i;
 
 
        a_assert(var && *var);
        a_assert(var && *var);
        a_assert(value);
        a_assert(value);
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
 
 
        for (i = ep->variableMax - 1; i >= 0; i--) {
        for (i = ep->variableMax - 1; i >= 0; i--) {
                if ((sp = symLookup(ep->variables[i] - EJ_OFFSET, var)) == NULL) {
                if ((sp = symLookup(ep->variables[i] - EJ_OFFSET, var)) == NULL) {
                        continue;
                        continue;
                }
                }
                a_assert(sp->content.type == string);
                a_assert(sp->content.type == string);
                *value = sp->content.value.string;
                *value = sp->content.value.string;
                return i;
                return i;
        }
        }
        return -1;
        return -1;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
#if UNUSED
#if UNUSED
/*
/*
 *      Get the variable symbol table
 *      Get the variable symbol table
 */
 */
 
 
sym_fd_t ejGetVariableTable(int eid)
sym_fd_t ejGetVariableTable(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        return ep->variables;
        return ep->variables;
}
}
#endif
#endif
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get the functions symbol table
 *      Get the functions symbol table
 */
 */
 
 
sym_fd_t ejGetFunctionTable(int eid)
sym_fd_t ejGetFunctionTable(int eid)
{
{
        ej_t    *ep;
        ej_t    *ep;
 
 
        if ((ep = ejPtr(eid)) == NULL) {
        if ((ep = ejPtr(eid)) == NULL) {
                return -1;
                return -1;
        }
        }
        return ep->functions;
        return ep->functions;
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Free an argument list
 *      Free an argument list
 */
 */
 
 
static void freeFunc(ejfunc_t *func)
static void freeFunc(ejfunc_t *func)
{
{
        int     i;
        int     i;
 
 
        for (i = func->nArgs - 1; i >= 0; i--) {
        for (i = func->nArgs - 1; i >= 0; i--) {
                bfree(B_L, func->args[i]);
                bfree(B_L, func->args[i]);
                func->nArgs = hFree((void***) &func->args, i);
                func->nArgs = hFree((void***) &func->args, i);
        }
        }
        if (func->fname) {
        if (func->fname) {
                bfree(B_L, func->fname);
                bfree(B_L, func->fname);
                func->fname = NULL;
                func->fname = NULL;
        }
        }
}
}
 
 
/******************************************************************************/
/******************************************************************************/
/*
/*
 *      Get Ejscript pointer
 *      Get Ejscript pointer
 */
 */
 
 
static ej_t *ejPtr(int eid)
static ej_t *ejPtr(int eid)
{
{
        a_assert(0 <= eid && eid < ejMax);
        a_assert(0 <= eid && eid < ejMax);
 
 
        if (eid < 0 || eid >= ejMax || ejHandles[eid] == NULL) {
        if (eid < 0 || eid >= ejMax || ejHandles[eid] == NULL) {
                ejError(NULL, T("Bad handle %d"), eid);
                ejError(NULL, T("Bad handle %d"), eid);
                return NULL;
                return NULL;
        }
        }
        return ejHandles[eid];
        return ejHandles[eid];
}
}
 
 
/******************************************************************************/
/******************************************************************************/
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.