⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ejparse.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ejparse.c -- Ejscript(TM) Parser * * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved. * * See the file "license.txt" for usage and redistribution license requirements *//******************************** Description *********************************//* *	Ejscript parser. This implementes a subset of the JavaScript language. *	Multiple Ejscript parsers can be opened at a time. *//********************************** Includes **********************************/#include	"ejIntrn.h"#if CE	#include	"CE/wincompat.h"#endif/********************************** Local Data ********************************/ej_t			**ejHandles;							/* List of ej handles */int				ejMax = -1;								/* Maximum size of	*//****************************** Forward Declarations **************************/#ifndef B_STATS#define	setString(a,b,c)	 setstring(b,c)#endifstatic ej_t		*ejPtr(int eid);static void		clearString(char_t **ptr);static void		setString(B_ARGS_DEC, char_t **ptr, char_t *s);static void		appendString(char_t **ptr, char_t *s);static int		parse(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		parseArgs(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		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		evalFunction(ej_t *ep);static void		freeFunc(ejfunc_t *func);static void		ejRemoveNewlines(ej_t *ep, int state);/************************************* Code ***********************************//* *	Initialize a Ejscript engine */int ejOpenEngine(sym_fd_t variables, sym_fd_t functions){	ej_t	*ep;	int		eid, vid;	if ((eid = hAllocEntry((void***) &ejHandles, &ejMax, sizeof(ej_t))) < 0) {		return -1;	}	ep = ejHandles[eid];	ep->eid = eid;/* *	Create a top level symbol table if one is not provided for variables and *	functions. Variables may create other symbol tables for block level *	declarations so we use hAlloc to manage a list of variable tables. */	if ((vid = hAlloc((void***) &ep->variables)) < 0) {		ejMax = hFree((void***) &ejHandles, ep->eid);		return -1;	}	if (vid >= ep->variableMax) {		ep->variableMax = vid + 1;	}	if (variables == -1) {		ep->variables[vid] = symOpen(64) + EJ_OFFSET;		ep->flags |= FLAGS_VARIABLES;	} else {		ep->variables[vid] = variables + EJ_OFFSET;	}	if (functions == -1) {		ep->functions = symOpen(64);		ep->flags |= FLAGS_FUNCTIONS;	} else {		ep->functions = functions;	}	ejLexOpen(ep);/* *	Define standard constants */	ejSetGlobalVar(ep->eid, T("null"), NULL);#if EMF	ejEmfOpen(ep->eid);#endif	return ep->eid;}/******************************************************************************//* *	Close */void ejCloseEngine(int eid){	ej_t	*ep;	int		i;	if ((ep = ejPtr(eid)) == NULL) {		return;	}#if EMF	ejEmfClose(eid);#endif	bfreeSafe(B_L, ep->error);	ep->error = NULL;	bfreeSafe(B_L, ep->result);	ep->result = NULL;	ejLexClose(ep);	for (i = ep->variableMax - 1; i >= 0; i--) {		if (ep->flags & FLAGS_VARIABLES) {			symClose(ep->variables[i] - EJ_OFFSET);		}		ep->variableMax = hFree((void***) &ep->variables, i);	}	if (ep->flags & FLAGS_FUNCTIONS) {		symClose(ep->functions);	}	ejMax = hFree((void***) &ejHandles, ep->eid);	bfree(B_L, ep);}#ifndef __NO_EJ_FILE/******************************************************************************//* *	Evaluate a Ejscript file */char_t *ejEvalFile(int eid, char_t *path, char_t **emsg){	gstat_t sbuf;	ej_t	*ep;	char_t	*script, *rs;	char	*fileBuf;	int		fd;	a_assert(path && *path);	if (emsg) {		*emsg = NULL;	}	if ((ep = ejPtr(eid)) == NULL) {		return NULL;	}	if ((fd = gopen(path, O_RDONLY | O_BINARY, 0666)) < 0) {		ejError(ep, T("Bad handle %d"), eid);		return NULL;	}		if (gstat(path, &sbuf) < 0) {		gclose(fd);		ejError(ep, T("Cant stat %s"), path);		return NULL;	}		if ((fileBuf = balloc(B_L, sbuf.st_size + 1)) == NULL) {		gclose(fd);		ejError(ep, T("Cant malloc %d"), sbuf.st_size);		return NULL;	}		if (gread(fd, fileBuf, sbuf.st_size) != (int)sbuf.st_size) {		gclose(fd);		bfree(B_L, fileBuf);		ejError(ep, T("Error reading %s"), path);		return NULL;	}		fileBuf[sbuf.st_size] = '\0';	gclose(fd);	if ((script = ballocAscToUni(fileBuf, sbuf.st_size)) == NULL) {		bfree(B_L, fileBuf);		ejError(ep, T("Cant malloc %d"), sbuf.st_size + 1);		return NULL;	}	bfree(B_L, fileBuf);	rs = ejEvalBlock(eid, script, emsg);	bfree(B_L, script);	return rs;}#endif /* __NO_EJ_FILE *//******************************************************************************//* *	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 *	ejCloseBlock when the evaluations are complete. */int ejOpenBlock(int eid){	ej_t	*ep;	int		vid;	if((ep = ejPtr(eid)) == NULL) {		return -1;	}	if ((vid = hAlloc((void***) &ep->variables)) < 0) {		return -1;	}	if (vid >= ep->variableMax) {		ep->variableMax = vid + 1;	}	ep->variables[vid] = symOpen(64) + EJ_OFFSET;	return vid;}/******************************************************************************//* *	Close a variable scope block. The vid parameter is the return value from *	the call to ejOpenBlock */int ejCloseBlock(int eid, int vid){	ej_t	*ep;	if((ep = ejPtr(eid)) == NULL) {		return -1;	}	symClose(ep->variables[vid] - EJ_OFFSET);	ep->variableMax = hFree((void***) &ep->variables, vid);	return 0;}/******************************************************************************//* *	Create a new variable scope block and evaluate a script. All variables *	created during this context will be automatically deleted when complete. */char_t *ejEvalBlock(int eid, char_t *script, char_t **emsg){	char_t* returnVal;	int		vid;	a_assert(script);	vid = ejOpenBlock(eid);	returnVal = ejEval(eid, script, emsg);	ejCloseBlock(eid, vid);	return returnVal;}/******************************************************************************//* *	Parse and evaluate a Ejscript. The caller may provide a symbol table to *	use for variables and function definitions. Return char_t pointer on *	success otherwise NULL pointer is returned. */char_t *ejEval(int eid, char_t *script, char_t **emsg){	ej_t	*ep;	ejinput_t	*oldBlock;	int		state;	void	*endlessLoopTest;	int		loopCounter;			a_assert(script);	if (emsg) {		*emsg = NULL;	} 	if ((ep = ejPtr(eid)) == NULL) {		return NULL;	}	setString(B_L, &ep->result, T(""));/* *	Allocate a new evaluation block, and save the old one */	oldBlock = ep->input;	ejLexOpenScript(ep, script);/* *	Do the actual parsing and evaluation */	loopCounter = 0;	endlessLoopTest = NULL;	do {		state = parse(ep, STATE_BEGIN, FLAGS_EXE);		if (state == STATE_RET) {			state = STATE_EOF;		}/* *		prevent parser from going into infinite loop.  If parsing the same *		line 10 times then fail and report Syntax error.  Most normal error *		are caught in the parser itself. */		if (endlessLoopTest == ep->input->script.servp) {			if (loopCounter++ > 10) {				state = STATE_ERR;				ejError(ep, T("Syntax error"));			}		} else {			endlessLoopTest = ep->input->script.servp;			loopCounter = 0;		}	} while (state != STATE_EOF && state != STATE_ERR);	ejLexCloseScript(ep);/* *	Return any error string to the user */	if (state == STATE_ERR && emsg) {		*emsg = bstrdup(B_L, ep->error);	}/* *	Restore the old evaluation block */	ep->input = oldBlock;	if (state == STATE_EOF) {		return ep->result;	}	if (state == STATE_ERR) {		return NULL;	}	return ep->result;}/******************************************************************************//* *	Recursive descent parser for Ejscript */static int parse(ej_t *ep, int state, int flags){	a_assert(ep);	switch (state) {/* *	Any statement, function arguments or conditional expressions */	case STATE_STMT:		if ((state = parseStmt(ep, state, flags)) != STATE_STMT_DONE &&			state != STATE_EOF && state != STATE_STMT_BLOCK_DONE &&			state != STATE_RET) {			state = STATE_ERR;		}		break;	case STATE_DEC:		if ((state = parseStmt(ep, state, flags)) != STATE_DEC_DONE &&			state != STATE_EOF) {			state = STATE_ERR;		}		break;	case STATE_EXPR:		if ((state = parseStmt(ep, state, flags)) != STATE_EXPR_DONE &&			state != STATE_EOF) {			state = STATE_ERR;		}		break;/* *	Variable declaration list */	case STATE_DEC_LIST:		state = parseDeclaration(ep, state, flags);		break;/* *	Function argument string */	case STATE_ARG_LIST:		state = parseArgs(ep, state, flags);		break;/* *	Logical condition list (relational operations separated by &&, ||) */	case STATE_COND:		state = parseCond(ep, state, flags);		break;/* *	Expression list */	case STATE_RELEXP:		state = parseExpr(ep, state, flags);		break;	}	if (state == STATE_ERR && ep->error == NULL) {		ejError(ep, T("Syntax error"));	}	return state;}/******************************************************************************//* *	Parse any statement including functions and simple relational operations */static int parseStmt(ej_t *ep, int state, int flags){	ejfunc_t	func;	ejfunc_t	*saveFunc;	ejinput_t	condScript, endScript, bodyScript, incrScript;	char_t		*value,	*identifier;	int			done, expectSemi, thenFlags, elseFlags, tid, cond, forFlags;	int			ejVarType;	a_assert(ep);/* *	Set these to NULL, else we try to free them if an error occurs. */	endScript.putBackToken = NULL;	bodyScript.putBackToken = NULL;	incrScript.putBackToken = NULL;	condScript.putBackToken = NULL;	expectSemi = 0;	saveFunc = NULL;	for (done = 0; !done; ) {		tid = ejLexGetToken(ep, state);		switch (tid) {		default:			ejLexPutbackToken(ep, TOK_EXPR, ep->token);			done++;			break;		case TOK_ERR:			state = STATE_ERR;			done++;			break;		case TOK_EOF:			state = STATE_EOF;			done++;			break;		case TOK_NEWLINE:			break;		case TOK_SEMI:/* *			This case is when we discover no statement and just a lone ';' */			if (state != STATE_STMT) {				ejLexPutbackToken(ep, tid, ep->token);			}			done++;			break;		case TOK_ID:/* *			This could either be a reference to a variable or an assignment */			identifier = NULL;			setString(B_L, &identifier, ep->token);/* *			Peek ahead to see if this is an assignment */			tid = ejLexGetToken(ep, state);			if (tid == TOK_ASSIGNMENT) {				if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {					clearString(&identifier);					goto error;				}				if (flags & FLAGS_EXE) {					if ( state == STATE_DEC ) {						ejSetLocalVar(ep->eid, identifier, ep->result);					} else {						ejVarType = ejGetVar(ep->eid, identifier, &value);						if (ejVarType > 0) {							ejSetLocalVar(ep->eid, identifier, ep->result);						} else {							ejSetGlobalVar(ep->eid, identifier, ep->result);						}					}				}			} else if (tid == TOK_INC_DEC ) {				value = NULL;				if (flags & FLAGS_EXE) {					ejVarType = ejGetVar(ep->eid, identifier, &value);					if (ejVarType < 0) {						ejError(ep, T("Undefined variable %s\n"), identifier);						goto error;					}					setString(B_L, &ep->result, value);					if (evalExpr(ep, value, (int) *ep->token, T("1")) < 0) {						state = STATE_ERR;						break;					}					if (ejVarType > 0) {						ejSetLocalVar(ep->eid, identifier, ep->result);					} else {						ejSetGlobalVar(ep->eid, identifier, ep->result);					}				}			} else {/* *				If we are processing a declaration, allow undefined vars */				value = NULL;				if (state == STATE_DEC) {					if (ejGetVar(ep->eid, identifier, &value) > 0) {						ejError(ep, T("Variable already declared"),							identifier);						clearString(&identifier);						goto error;					}					ejSetLocalVar(ep->eid, identifier, NULL);				} else {					if ( flags & FLAGS_EXE ) {						if (ejGetVar(ep->eid, identifier, &value) < 0) {							ejError(ep, T("Undefined variable %s\n"),								identifier);							clearString(&identifier);							goto error;						}					}				}				setString(B_L, &ep->result, value);				ejLexPutbackToken(ep, tid, ep->token);			}			clearString(&identifier);			if (state == STATE_STMT) {				expectSemi++;			}			done++;			break;		case TOK_LITERAL:/* *			Set the result to the literal (number or string constant) */			setString(B_L, &ep->result, ep->token);			if (state == STATE_STMT) {				expectSemi++;			}			done++;			break;		case TOK_FUNCTION:/* *			We must save any current ep->func value for the current stack frame */			if (ep->func) {				saveFunc = ep->func;			}			memset(&func, 0, sizeof(ejfunc_t));			setString(B_L, &func.fname, ep->token);			ep->func = &func;			setString(B_L, &ep->result, T(""));			if (ejLexGetToken(ep, state) != TOK_LPAREN) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -