?? ejparse.c
字號:
if (ejLexGetToken(ep, state) != TOK_LPAREN) {
freeFunc(&func);
goto error;
}
if (parse(ep, STATE_ARG_LIST, flags) != STATE_ARG_LIST_DONE) {
freeFunc(&func);
ep->func = saveFunc;
goto error;
}
/*
* Evaluate the function if required
*/
if (flags & FLAGS_EXE && evalFunction(ep) < 0) {
freeFunc(&func);
ep->func = saveFunc;
goto error;
}
freeFunc(&func);
ep->func = saveFunc;
if (ejLexGetToken(ep, state) != TOK_RPAREN) {
goto error;
}
if (state == STATE_STMT) {
expectSemi++;
}
done++;
break;
case TOK_IF:
if (state != STATE_STMT) {
goto error;
}
if (ejLexGetToken(ep, state) != TOK_LPAREN) {
goto error;
}
/*
* Evaluate the entire condition list "(condition)"
*/
if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
goto error;
}
if (ejLexGetToken(ep, state) != TOK_RPAREN) {
goto error;
}
/*
* This is the "then" case. We need to always parse both cases and
* execute only the relevant case.
*/
if (*ep->result == '1') {
thenFlags = flags;
elseFlags = flags & ~FLAGS_EXE;
} else {
thenFlags = flags & ~FLAGS_EXE;
elseFlags = flags;
}
/*
* Process the "then" case. Allow for RETURN statement
*/
switch (parse(ep, STATE_STMT, thenFlags)) {
case STATE_RET:
return STATE_RET;
case STATE_STMT_DONE:
break;
default:
goto error;
}
/*
* check to see if there is an "else" case
*/
ejRemoveNewlines(ep, state);
tid = ejLexGetToken(ep, state);
if (tid != TOK_ELSE) {
ejLexPutbackToken(ep, tid, ep->token);
done++;
break;
}
/*
* Process the "else" case. Allow for return.
*/
switch (parse(ep, STATE_STMT, elseFlags)) {
case STATE_RET:
return STATE_RET;
case STATE_STMT_DONE:
break;
default:
goto error;
}
done++;
break;
case TOK_FOR:
/*
* Format for the expression is:
*
* for (initial; condition; incr) {
* body;
* }
*/
if (state != STATE_STMT) {
goto error;
}
if (ejLexGetToken(ep, state) != TOK_LPAREN) {
goto error;
}
/*
* Evaluate the for loop initialization statement
*/
if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
goto error;
}
if (ejLexGetToken(ep, state) != TOK_SEMI) {
goto error;
}
/*
* The first time through, we save the current input context just
* to each step: prior to the conditional, the loop increment and the
* loop body.
*/
ejLexSaveInputState(ep, &condScript);
if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
goto error;
}
cond = (*ep->result != '0');
if (ejLexGetToken(ep, state) != TOK_SEMI) {
goto error;
}
/*
* Don't execute the loop increment statement or the body first time
*/
forFlags = flags & ~FLAGS_EXE;
ejLexSaveInputState(ep, &incrScript);
if (parse(ep, STATE_EXPR, forFlags) != STATE_EXPR_DONE) {
goto error;
}
if (ejLexGetToken(ep, state) != TOK_RPAREN) {
goto error;
}
/*
* Parse the body and remember the end of the body script
*/
ejLexSaveInputState(ep, &bodyScript);
if (parse(ep, STATE_STMT, forFlags) != STATE_STMT_DONE) {
goto error;
}
ejLexSaveInputState(ep, &endScript);
/*
* Now actually do the for loop. Note loop has been rotated
*/
while (cond && (flags & FLAGS_EXE) ) {
/*
* Evaluate the body
*/
ejLexRestoreInputState(ep, &bodyScript);
switch (parse(ep, STATE_STMT, flags)) {
case STATE_RET:
return STATE_RET;
case STATE_STMT_DONE:
break;
default:
goto error;
}
/*
* Evaluate the increment script
*/
ejLexRestoreInputState(ep, &incrScript);
if (parse(ep, STATE_EXPR, flags) != STATE_EXPR_DONE) {
goto error;
}
/*
* Evaluate the condition
*/
ejLexRestoreInputState(ep, &condScript);
if (parse(ep, STATE_COND, flags) != STATE_COND_DONE) {
goto error;
}
cond = (*ep->result != '0');
}
ejLexRestoreInputState(ep, &endScript);
done++;
break;
case TOK_VAR:
if (parse(ep, STATE_DEC_LIST, flags) != STATE_DEC_LIST_DONE) {
goto error;
}
done++;
break;
case TOK_COMMA:
ejLexPutbackToken(ep, TOK_EXPR, ep->token);
done++;
break;
case TOK_LPAREN:
if (state == STATE_EXPR) {
if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
goto error;
}
if (ejLexGetToken(ep, state) != TOK_RPAREN) {
goto error;
}
return STATE_EXPR_DONE;
}
done++;
break;
case TOK_RPAREN:
ejLexPutbackToken(ep, tid, ep->token);
return STATE_EXPR_DONE;
case TOK_LBRACE:
/*
* This handles any code in braces except "if () {} else {}"
*/
if (state != STATE_STMT) {
goto error;
}
/*
* Parse will return STATE_STMT_BLOCK_DONE when the RBRACE is seen
*/
do {
state = parse(ep, STATE_STMT, flags);
} while (state == STATE_STMT_DONE);
/*
* Allow return statement.
*/
if (state == STATE_RET) {
return state;
}
if (ejLexGetToken(ep, state) != TOK_RBRACE) {
goto error;
}
return STATE_STMT_DONE;
case TOK_RBRACE:
if (state == STATE_STMT) {
ejLexPutbackToken(ep, tid, ep->token);
return STATE_STMT_BLOCK_DONE;
}
goto error;
case TOK_RETURN:
if (parse(ep, STATE_RELEXP, flags) != STATE_RELEXP_DONE) {
goto error;
}
if (flags & FLAGS_EXE) {
while ( ejLexGetToken(ep, state) != TOK_EOF );
done++;
return STATE_RET;
}
break;
}
}
if (expectSemi) {
tid = ejLexGetToken(ep, state);
if (tid != TOK_SEMI && tid != TOK_NEWLINE) {
goto error;
}
/*
* Skip newline after semi-colon
*/
ejRemoveNewlines(ep, state);
}
/*
* Free resources and return the correct status
*/
doneParse:
if (tid == TOK_FOR) {
ejLexFreeInputState(ep, &condScript);
ejLexFreeInputState(ep, &incrScript);
ejLexFreeInputState(ep, &endScript);
ejLexFreeInputState(ep, &bodyScript);
}
if (state == STATE_STMT) {
return STATE_STMT_DONE;
} else if (state == STATE_DEC) {
return STATE_DEC_DONE;
} else if (state == STATE_EXPR) {
return STATE_EXPR_DONE;
} else if (state == STATE_EOF) {
return state;
} else {
return STATE_ERR;
}
/*
* Common error exit
*/
error:
state = STATE_ERR;
goto doneParse;
}
/******************************************************************************/
/*
* Parse variable declaration list
*/
static int parseDeclaration(ej_t *ep, int state, int flags)
{
int tid;
a_assert(ep);
/*
* Declarations can be of the following forms:
* var x;
* var x, y, z;
* var x = 1 + 2 / 3, y = 2 + 4;
*
* We set the variable to NULL if there is no associated assignment.
*/
do {
if ((tid = ejLexGetToken(ep, state)) != TOK_ID) {
return STATE_ERR;
}
ejLexPutbackToken(ep, tid, ep->token);
/*
* Parse the entire assignment or simple identifier declaration
*/
if (parse(ep, STATE_DEC, flags) != STATE_DEC_DONE) {
return STATE_ERR;
}
/*
* Peek at the next token, continue if comma seen
*/
tid = ejLexGetToken(ep, state);
if (tid == TOK_SEMI) {
return STATE_DEC_LIST_DONE;
} else if (tid != TOK_COMMA) {
return STATE_ERR;
}
} while (tid == TOK_COMMA);
if (tid != TOK_SEMI) {
return STATE_ERR;
}
return STATE_DEC_LIST_DONE;
}
/******************************************************************************/
/*
* Parse function arguments
*/
static int parseArgs(ej_t *ep, int state, int flags)
{
int tid, aid;
a_assert(ep);
do {
state = parse(ep, STATE_RELEXP, flags);
if (state == STATE_EOF || state == STATE_ERR) {
return state;
}
if (state == STATE_RELEXP_DONE) {
aid = hAlloc((void***) &ep->func->args);
ep->func->args[aid] = bstrdup(B_L, ep->result);
ep->func->nArgs++;
}
/*
* Peek at the next token, continue if more args (ie. comma seen)
*/
tid = ejLexGetToken(ep, state);
if (tid != TOK_COMMA) {
ejLexPutbackToken(ep, tid, ep->token);
}
} while (tid == TOK_COMMA);
if (tid != TOK_RPAREN && state != STATE_RELEXP_DONE) {
return STATE_ERR;
}
return STATE_ARG_LIST_DONE;
}
/******************************************************************************/
/*
* Parse conditional expression (relational ops separated by ||, &&)
*/
static int parseCond(ej_t *ep, int state, int flags)
{
char_t *lhs, *rhs;
int tid, operator;
a_assert(ep);
setString(B_L, &ep->result, T(""));
rhs = lhs = NULL;
operator = 0;
do {
/*
* Recurse to handle one side of a conditional. Accumulate the
* left hand side and the final result in ep->result.
*/
state = parse(ep, STATE_RELEXP, flags);
if (state != STATE_RELEXP_DONE) {
state = STATE_ERR;
break;
}
if (operator > 0) {
setString(B_L, &rhs, ep->result);
if (evalCond(ep, lhs, operator, rhs) < 0) {
state = STATE_ERR;
break;
}
}
setString(B_L, &lhs, ep->result);
tid = ejLexGetToken(ep, state);
if (tid == TOK_LOGICAL) {
operator = (int) *ep->token;
} else if (tid == TOK_RPAREN || tid == TOK_SEMI) {
ejLexPutbackToken(ep, tid, ep->token);
state = STATE_COND_DONE;
break;
} else {
ejLexPutbackToken(ep, tid, ep->token);
}
} while (state == STATE_RELEXP_DONE);
if (lhs) {
bfree(B_L, lhs);
}
if (rhs) {
bfree(B_L, rhs);
}
return state;
}
/******************************************************************************/
/*
* Parse expression (leftHandSide operator rightHandSide)
*/
static int parseExpr(ej_t *ep, int state, int flags)
{
char_t *lhs, *rhs;
int rel, tid;
a_assert(ep);
setString(B_L, &ep->result, T(""));
rhs = lhs = NULL;
rel = 0;
tid = 0;
do {
/*
* This loop will handle an entire expression list. We call parse
* to evalutate each term which returns the result in ep->result.
*/
if (tid == TOK_LOGICAL) {
if ((state = parse(ep, STATE_RELEXP, flags)) != STATE_RELEXP_DONE) {
state = STATE_ERR;
break;
}
} else {
if ((state = parse(ep, STATE_EXPR, flags)) != STATE_EXPR_DONE) {
state = STATE_ERR;
break;
}
}
if (rel > 0) {
setString(B_L, &rhs, ep->result);
if (tid == TOK_LOGICAL) {
if (evalCond(ep, lhs, rel, rhs) < 0) {
state = STATE_ERR;
break;
}
} else {
if (evalExpr(ep, lhs, rel, rhs) < 0) {
state = STATE_ERR;
break;
}
}
}
setString(B_L, &lhs, ep->result);
if ((tid = ejLexGetToken(ep, state)) == TOK_EXPR ||
tid == TOK_INC_DEC || tid == TOK_LOGICAL) {
rel = (int) *ep->token;
} else {
ejLexPutbackToken(ep, tid, ep->token);
state = STATE_RELEXP_DONE;
}
} while (state == STATE_EXPR_DONE);
if (rhs) {
bfree(B_L, rhs);
}
if (lhs) {
bfree(B_L, lhs);
}
return state;
}
/******************************************************************************/
/*
* Evaluate a condition. Implements &&, ||, !
*/
static int evalCond(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
{
char_t buf[16];
int l, r, lval;
a_assert(lhs);
a_assert(rhs);
a_assert(rel > 0);
lval = 0;
if (gisdigit((int)*lhs) && gisdigit((int)*rhs)) {
l = gatoi(lhs);
r = gatoi(rhs);
switch (rel) {
case COND_AND:
lval = l && r;
break;
case COND_OR:
lval = l || r;
break;
default:
ejError(ep, T("Bad operator %d"), rel);
return -1;
}
} else {
if (!gisdigit((int)*lhs)) {
ejError(ep, T("Conditional must be numeric"), lhs);
} else {
ejError(ep, T("Conditional must be numeric"), rhs);
}
}
stritoa(lval, buf, sizeof(buf));
setString(B_L, &ep->result, buf);
return 0;
}
/******************************************************************************/
/*
* Evaluate an operation
*/
static int evalExpr(ej_t *ep, char_t *lhs, int rel, char_t *rhs)
{
char_t *cp, buf[16];
int numeric, l, r, lval;
a_assert(lhs);
a_assert(rhs);
a_assert(rel > 0);
/*
* All of the characters in the lhs and rhs must be numeric
*/
numeric = 1;
for (cp = lhs; *cp; cp++) {
if (!gisdigit((int)*cp)) {
numeric = 0;
break;
}
}
if (numeric) {
for (cp = rhs; *cp; cp++) {
if (!gisdigit((int)*cp)) {
numeric = 0;
break;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -