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 + -
显示快捷键?