📄 ejparse.c
字号:
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 + -