ejsparser.c

来自「samba最新软件」· C语言 代码 · 共 2,437 行 · 第 1/4 页

C
2,437
字号
/* *	@file 	ejsParser.c *	@brief 	EJS Parser and Execution  *//********************************* Copyright **********************************//* *	@copy	default.g *	 *	Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. *	Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved. *	 *	This software is distributed under commercial and open source licenses. *	You may use the GPL open source license described below or you may acquire  *	a commercial license from Mbedthis Software. You agree to be fully bound  *	by the terms of either license. Consult the LICENSE.TXT distributed with  *	this software for full details. *	 *	This software is open source; you can redistribute it and/or modify it  *	under the terms of the GNU General Public License as published by the  *	Free Software Foundation; either version 2 of the License, or (at your  *	option) any later version. See the GNU General Public License for more  *	details at: http://www.mbedthis.com/downloads/gplLicense.html *	 *	This program is distributed WITHOUT ANY WARRANTY; without even the  *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  *	 *	This GPL license does NOT permit incorporating this software into  *	proprietary programs. If you are unable to comply with the GPL, you must *	acquire a commercial license to use this software. Commercial licenses  *	for this software and support services are available from Mbedthis  *	Software at http://www.mbedthis.com  *	 *	@end *//********************************** Includes **********************************/#include	"ejsInternal.h"#if BLD_FEATURE_EJS/****************************** Forward Declarations **************************/static void 	appendValue(MprVar *v1, MprVar *v2);static int		evalCond(Ejs *ep, MprVar *lhs, int rel, MprVar *rhs);static int		evalExpr(Ejs *ep, MprVar *lhs, int rel, MprVar *rhs);#if BLD_FEATURE_FLOATING_POINTstatic int 		evalFloatExpr(Ejs *ep, double l, int rel, double r);#endif static int 		evalBoolExpr(Ejs *ep, bool l, int rel, bool r);static int 		evalPtrExpr(Ejs *ep, void *l, int rel, void *r);static int 		evalNumericExpr(Ejs *ep, MprNum l, int rel, MprNum r);static int 		evalStringExpr(Ejs *ep, MprVar *lhs, int rel, MprVar *rhs);static int		evalFunction(Ejs *ep, MprVar *obj, int flags);static void		freeProc(EjsProc *proc);static int		parseArgs(Ejs *ep, int state, int flags);static int		parseAssignment(Ejs *ep, int state, int flags, char *id, 					char *fullName);static int		parseCond(Ejs *ep, int state, int flags);static int		parseDeclaration(Ejs *ep, int state, int flags);static int		parseExpr(Ejs *ep, int state, int flags);static int 		parseFor(Ejs *ep, int state, int flags);static int 		parseForIn(Ejs *ep, int state, int flags);static int		parseFunctionDec(Ejs *ep, int state, int flags);static int		parseFunction(Ejs *ep, int state, int flags, char *id);static int 		parseId(Ejs *ep, int state, int flags, char **id, 					char **fullName, int *fullNameLen, int *done);static int 		parseInc(Ejs *ep, int state, int flags);static int 		parseIf(Ejs *ep, int state, int flags, int *done);static int		parseStmt(Ejs *ep, int state, int flags);static void 	removeNewlines(Ejs *ep, int state);static void 	updateResult(Ejs *ep, int state, int flags, MprVar *vp);/************************************* Code ***********************************//* *	Recursive descent parser for EJS */int ejsParse(Ejs *ep, int state, int flags){	mprAssert(ep);	switch (state) {	/*	 *	Any statement, function arguments or conditional expressions	 */	case EJS_STATE_STMT:		if ((state = parseStmt(ep, state, flags)) != EJS_STATE_STMT_DONE &&			state != EJS_STATE_EOF && state != EJS_STATE_STMT_BLOCK_DONE &&			state != EJS_STATE_RET) {			state = EJS_STATE_ERR;		}		break;	case EJS_STATE_DEC:		if ((state = parseStmt(ep, state, flags)) != EJS_STATE_DEC_DONE &&			state != EJS_STATE_EOF) {			state = EJS_STATE_ERR;		}		break;	case EJS_STATE_EXPR:		if ((state = parseStmt(ep, state, flags)) != EJS_STATE_EXPR_DONE &&			state != EJS_STATE_EOF) {			state = EJS_STATE_ERR;		}		break;	/*	 *	Variable declaration list	 */	case EJS_STATE_DEC_LIST:		state = parseDeclaration(ep, state, flags);		break;	/*	 *	Function argument string	 */	case EJS_STATE_ARG_LIST:		state = parseArgs(ep, state, flags);		break;	/*	 *	Logical condition list (relational operations separated by &&, ||)	 */	case EJS_STATE_COND:		state = parseCond(ep, state, flags);		break;	/*	 *	Expression list	 */	case EJS_STATE_RELEXP:		state = parseExpr(ep, state, flags);		break;	}	if (state == EJS_STATE_ERR && ep->error == NULL) {		ejsError(ep, "Syntax error");	}	return state;}/******************************************************************************//* *	Parse any statement including functions and simple relational operations */static int parseStmt(Ejs *ep, int state, int flags){	EjsProc		*saveProc;	MprVar		*vp, *saveObj;	char		*id, *fullName, *initToken;	int 		done, expectSemi, tid, fullNameLen, rel;	int 		initId;	mprAssert(ep);	expectSemi = 0;	saveProc = NULL;	id = 0;	fullName = 0;	fullNameLen = 0;	ep->currentObj = 0;	ep->currentProperty = 0;	for (done = 0; !done && state != EJS_STATE_ERR; ) {		tid = ejsLexGetToken(ep, state);		switch (tid) {		default:			ejsLexPutbackToken(ep, EJS_TOK_EXPR, ep->token);			done++;			break;		case EJS_TOK_EXPR:			rel = (int) *ep->token;			if (state == EJS_STATE_EXPR) {				ejsLexPutbackToken(ep, EJS_TOK_EXPR, ep->token);			}			done++;			break;		case EJS_TOK_LOGICAL:			ejsLexPutbackToken(ep, tid, ep->token);			done++;			break;		case EJS_TOK_ERR:			state = EJS_STATE_ERR;			done++;			break;		case EJS_TOK_EOF:			state = EJS_STATE_EOF;			done++;			break;		case EJS_TOK_NEWLINE:			break;		case EJS_TOK_SEMI:			/*			 *	This case is when we discover no statement and just a lone ';'			 */			if (state != EJS_STATE_STMT) {				ejsLexPutbackToken(ep, tid, ep->token);			}			done++;			break;		case EJS_TOK_PERIOD:			if (flags & EJS_FLAGS_EXE) {				if (ep->currentProperty == 0) {					ejsError(ep, "Undefined object \"%s\"\n", id);					goto error;				}			}			ep->currentObj = ep->currentProperty;			if ((tid = ejsLexGetToken(ep, state)) != EJS_TOK_ID) {				ejsError(ep, "Bad property after '.': %s\n", ep->token);				goto error;			}			mprFree(id);			id = mprStrdup(ep->token);			vp = ejsFindProperty(ep, state, ep->currentObj, id, flags);			updateResult(ep, state, flags, vp);#if BLD_DEBUG			fullNameLen = mprReallocStrcat(&fullName, MPR_MAX_VAR, fullNameLen,				0, ".", NULL);#endif			ep->currentProperty = vp;			ejsLexPutbackToken(ep, tid, ep->token);			break;		case EJS_TOK_LBRACKET:			ep->currentObj = ep->currentProperty;			saveObj = ep->currentObj;			if (ejsParse(ep, EJS_STATE_RELEXP, flags) != EJS_STATE_RELEXP_DONE){				goto error;			}			ep->currentObj = saveObj;			mprFree(id);			mprVarToString(&id, MPR_MAX_STRING, 0, &ep->result);			if (id[0] == '\0') {				if (flags & EJS_FLAGS_EXE) {					ejsError(ep, 						"[] expression evaluates to the empty string\n");					goto error;				}			} else {				vp = ejsFindProperty(ep, state, ep->currentObj, id, flags);				ep->currentProperty = vp;				updateResult(ep, state, flags, vp);			}#if BLD_DEBUG			if (id[0] && strlen(id) < (MPR_MAX_VAR / 2)) {				/*				 *	If not executing yet, id may not be known				 */				fullNameLen = mprReallocStrcat(&fullName, MPR_MAX_VAR, 					fullNameLen, 0, "[", id, "]", NULL);			}#endif			if ((tid = ejsLexGetToken(ep, state)) != EJS_TOK_RBRACKET) {				ejsError(ep, "Missing ']'\n");				goto error;			}			break;		case EJS_TOK_ID:			state = parseId(ep, state, flags, &id, &fullName, &fullNameLen, 				&done);			if (done && state == EJS_STATE_STMT) {				expectSemi++;			}			break;		case EJS_TOK_ASSIGNMENT:			state = parseAssignment(ep, state, flags, id, fullName);			if (state == EJS_STATE_STMT) {				expectSemi++;				done++;			}			break;		case EJS_TOK_INC_DEC:			state = parseInc(ep, state, flags);			if (state == EJS_STATE_STMT) {				expectSemi++;			}			break;		case EJS_TOK_NEW:			if (ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_NEW) 					!= EJS_STATE_EXPR_DONE) {				goto error;			}			break;		case EJS_TOK_DELETE:			if (ejsParse(ep, EJS_STATE_EXPR, 					flags | EJS_FLAGS_DELETE) != EJS_STATE_EXPR_DONE) {				goto error;			}			if (flags & EJS_FLAGS_EXE) {				mprDeleteProperty(ep->currentObj, ep->currentProperty->name);			}			done++;			break;		case EJS_TOK_FUNCTION:			state = parseFunctionDec(ep, state, flags);			done++;			break;		case EJS_TOK_LITERAL:			/*			 *	Set the result to the string literal 			 */			mprCopyVarValue(&ep->result, mprCreateStringVar(ep->token, 0), 				MPR_SHALLOW_COPY);			if (state == EJS_STATE_STMT) {				expectSemi++;			}			done++;			break;		case EJS_TOK_NUMBER:			/*			 *	Set the result to the parsed number			 */			mprCopyVar(&ep->result, &ep->tokenNumber, 0);			if (state == EJS_STATE_STMT) {				expectSemi++;			}			done++;			break;		case EJS_TOK_FUNCTION_NAME:			state = parseFunction(ep, state, flags, id);			if (state == EJS_STATE_STMT) {				expectSemi++;			}			if (ep->flags & EJS_FLAGS_EXIT) {				state = EJS_STATE_RET;			}			done++;			break;		case EJS_TOK_IF:			state = parseIf(ep, state, flags, &done);			if (state == EJS_STATE_RET) {				goto doneParse;			}			break;		case EJS_TOK_FOR:			if (state != EJS_STATE_STMT) {				goto error;			}			if (ejsLexGetToken(ep, state) != EJS_TOK_LPAREN) {				goto error;			}			/*			 *	Need to peek 2-3 tokens ahead and see if this is a 			 *		for ([var] x in set) 			 *	or			 *		for (init ; whileCond; incr)			 */			initId = ejsLexGetToken(ep, EJS_STATE_EXPR);			if (initId == EJS_TOK_ID && strcmp(ep->token, "var") == 0) {				/*	Simply eat var tokens */				initId = ejsLexGetToken(ep, EJS_STATE_EXPR);			}			initToken = mprStrdup(ep->token);			tid = ejsLexGetToken(ep, EJS_STATE_EXPR);			ejsLexPutbackToken(ep, tid, ep->token);			ejsLexPutbackToken(ep, initId, initToken);			mprFree(initToken);			if (tid == EJS_TOK_IN) {				if ((state = parseForIn(ep, state, flags)) < 0) {					goto error;				}			} else {				if ((state = parseFor(ep, state, flags)) < 0) {					goto error;				}			}			done++;			break;		case EJS_TOK_VAR:			if (ejsParse(ep, EJS_STATE_DEC_LIST, flags) 					!= EJS_STATE_DEC_LIST_DONE) {				goto error;			}			done++;			break;		case EJS_TOK_COMMA:			ejsLexPutbackToken(ep, tid, ep->token);			done++;			break;		case EJS_TOK_LPAREN:			if (state == EJS_STATE_EXPR) {				if (ejsParse(ep, EJS_STATE_RELEXP, flags) 						!= EJS_STATE_RELEXP_DONE) {					goto error;				}				if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {					goto error;				}			}			done++;			break;		case EJS_TOK_RPAREN:			ejsLexPutbackToken(ep, tid, ep->token);			done++;			break;		case EJS_TOK_LBRACE:			/*			 *	This handles any code in braces except "if () {} else {}"			 */			if (state != EJS_STATE_STMT) {				goto error;			}			/*			 *	Parse will return EJS_STATE_STMT_BLOCK_DONE when the RBRACE 			 *	is seen.			 */			do {				state = ejsParse(ep, EJS_STATE_STMT, flags);			} while (state == EJS_STATE_STMT_DONE);			if (state != EJS_STATE_RET) {				if (ejsLexGetToken(ep, state) != EJS_TOK_RBRACE) {					goto error;				}				state = EJS_STATE_STMT_DONE;			}			done++;			break;		case EJS_TOK_RBRACE:			if (state == EJS_STATE_STMT) {				ejsLexPutbackToken(ep, tid, ep->token);				state = EJS_STATE_STMT_BLOCK_DONE;				done++;				break;			}			goto error;		case EJS_TOK_RETURN:			if (ejsParse(ep, EJS_STATE_RELEXP, flags) 					!= EJS_STATE_RELEXP_DONE) {				goto error;			}			if (flags & EJS_FLAGS_EXE) {				while (ejsLexGetToken(ep, state) != EJS_TOK_EOF) {					;				}				state = EJS_STATE_RET;				done++;			}			break;		}	}	if (expectSemi) {		tid = ejsLexGetToken(ep, state);		if (tid != EJS_TOK_SEMI && tid != EJS_TOK_NEWLINE && 				tid != EJS_TOK_EOF) {			goto error;		}		/*		 *	Skip newline after semi-colon		 */		removeNewlines(ep, state);	}/* *	Free resources and return the correct status */doneParse:	mprFree(id);	mprFree(fullName);	/*	 *	Advance the state	 */	switch (state) {	case EJS_STATE_STMT:		return EJS_STATE_STMT_DONE;	case EJS_STATE_DEC:		return EJS_STATE_DEC_DONE;	case EJS_STATE_EXPR:		return EJS_STATE_EXPR_DONE;	case EJS_STATE_STMT_DONE:	case EJS_STATE_STMT_BLOCK_DONE:	case EJS_STATE_EOF:	case EJS_STATE_RET:		return state;	default:		return EJS_STATE_ERR;	}/* *	Common error exit */error:	state = EJS_STATE_ERR;	goto doneParse;}/******************************************************************************//* *	Parse function arguments */static int parseArgs(Ejs *ep, int state, int flags){	int		tid;	mprAssert(ep);	do {		/*		 *	Peek and see if there are no args		 */		tid = ejsLexGetToken(ep, state);		ejsLexPutbackToken(ep, tid, ep->token);		if (tid == EJS_TOK_RPAREN) {			break;		}		state = ejsParse(ep, EJS_STATE_RELEXP, flags);		if (state == EJS_STATE_EOF || state == EJS_STATE_ERR) {			return state;		}		if (state == EJS_STATE_RELEXP_DONE) {			if (flags & EJS_FLAGS_EXE) {				mprAssert(ep->proc->args);				mprAddToArray(ep->proc->args, 					mprDupVar(&ep->result, MPR_SHALLOW_COPY));			}		}		/*		 *	Peek at the next token, continue if more args (ie. comma seen)		 */		tid = ejsLexGetToken(ep, state);		if (tid != EJS_TOK_COMMA) {			ejsLexPutbackToken(ep, tid, ep->token);		}	} while (tid == EJS_TOK_COMMA);	if (tid != EJS_TOK_RPAREN && state != EJS_STATE_RELEXP_DONE) {		return EJS_STATE_ERR;	}	return EJS_STATE_ARG_LIST_DONE;}/******************************************************************************//* *	Parse an assignment statement */static int parseAssignment(Ejs *ep, int state, int flags, char *id, 	char *fullName){	MprVar		*vp, *saveProperty, *saveObj;	if (id == 0) {		return -1;	}	saveObj = ep->currentObj;	saveProperty = ep->currentProperty;	if (ejsParse(ep, EJS_STATE_RELEXP, flags | EJS_FLAGS_ASSIGNMENT) 			!= EJS_STATE_RELEXP_DONE) {		return -1;	}	ep->currentObj = saveObj;	ep->currentProperty = saveProperty;	if (! (flags & EJS_FLAGS_EXE)) {		return state;	}

⌨️ 快捷键说明

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