static double eval_expr(const char *buf, int *pos) /* expr = term+expr | term-expr | term */ { double rv = 0.0, lhs, rhs; Token tok; DB(printf("-- eval_expr(\"%s\", &pos=%p pos=%d)\n", buf+*pos, pos, *pos)); lhs = eval_term(buf, pos); if(G_eval_error) return rv; DB(printf("-- expr lhs=%f\n", lhs)); tok = pull_token(buf, pos); if(G_eval_error) return rv; DB(printf("-- expr token type '%c' = ", tok.type)); switch(tok.type) { case '\0': DB(printf("END OF BUFFER\n")); rv = lhs; break; case '+': /* addition */ rhs = eval_expr(buf, pos); DB(printf("%f+%f", lhs, rhs)); rv = lhs+rhs; DB(printf("=%f\n", rv)); break; case '-': /* subtraction */ rhs = eval_expr(buf, pos); DB(printf("%f-%f", lhs, rhs)); rv = lhs-rhs; DB(printf("=%f\n", rv)); break; case ')': /* end of group */ DB(printf("end group")); push_token(tok); rv = lhs; DB(printf(" (rv=%f)\n", rv)); break; case ',': /* argument delimiter */ DB(printf("delimiter")); push_token(tok); rv = lhs; DB(printf(" (rv=%f)\n", rv)); break; default: DB(printf("invalid expr token\n")); G_eval_error = EVAL_SYNTAX_ERROR; rv = lhs; } DB(printf("-- expr rv=%f\n", rv)); return rv; }
static double eval_fact(const char *buf, int *pos) /* fact = item^fact | item */ { double rv = 0.0, lhs, rhs; Token tok; DB(printf("-- eval_fact(\"%s\", &pos=%p pos=%d)\n", buf+*pos, pos, *pos)); lhs = eval_item(buf, pos); if(G_eval_error) return rv; DB(printf("-- fact lhs=%f\n", lhs)); tok = pull_token(buf, pos); if(G_eval_error) return rv; DB(printf("-- fact token type '%c' = ", tok.type)); switch(tok.type) { case '\0': DB(printf("END OF BUFFER\n")); rv = lhs; break; case '^': /* exponentiation */ rhs = eval_fact(buf, pos); DB(printf("%f^%f", lhs, rhs)); if(G_eval_error) return rv; rv = pow(lhs, rhs); DB(printf("=%f\n", rv)); break; default: DB(printf("PUSHBACK\n")); push_token(tok); rv = lhs; } DB(printf("-- fact rv=%f\n", rv)); return rv; }
static double eval_item(const char *buf, int *pos) /* item = -item | +item | int | var | (expr) */ { double rv = 0.0; void *data; int tlen, nargs, xargs; DB(int i); FunctionPtr fn; DB(char *fname); Token tok; DB(printf("-- eval_item(\"%s\", &pos=%p pos=%d)\n", buf+*pos, pos, *pos)); tok = pull_token(buf, pos); if(G_eval_error) return rv; DB(printf("-- item token type '%c' = ", tok.type)); switch(tok.type) { case '+': /* positive */ DB(printf("positive\n")); rv = eval_fact(buf, pos); break; case '-': /* negative */ DB(printf("negative\n")); rv = -eval_fact(buf, pos); break; case 'v': /* variable */ DB(printf("variable name '%s'=%f\n", tok.str, tok.value)); rv = tok.value; break; case 'f': /* function */ DB(printf("function name '%s'=%p(%d)\n", tok.str, tok.fn, tok.args)); tlen = tok.args; nargs = tok.args; xargs = nargs; data = tok.data; fn = tok.fn; DB(fname = tok.str); tok = pull_token(buf, pos); if(G_eval_error == 0) { if(tok.type != '(') G_eval_error = EVAL_SYNTAX_ERROR; else { double *targ = NULL; if(tlen > 0) { targ = (double*)lalloc(sizeof(double)*tlen); if(targ == NULL) { G_eval_error = EVAL_MEM_ERROR; break; } }else tlen = 0; if(eval_args(buf, pos, &nargs, &targ, &tlen, 0)) break; DB(printf("-- item %d arguments\n", nargs)); if(xargs < 0) { if(nargs < 1) { DB(printf("-- item too few arguments\n")); G_eval_error = EVAL_ARGS_ERROR; break; } }else if(nargs != xargs) { DB(printf("-- item bad argument count (%d) need %d\n", nargs, xargs)); G_eval_error = EVAL_ARGS_ERROR; break; } tok = pull_token(buf, pos); if(tok.type != ')') G_eval_error = EVAL_SYNTAX_ERROR; else if(G_eval_error == 0) { DB(printf("-- call function [%p] with %d args [%p]\n", fn, nargs, targ)); DB(printf("-- %s(%f", fname, targ[0])); DB(for(i=1;i<nargs;i++)printf(",%f",targ[i])); DB(printf(")\n")); if(fn(nargs, targ, &rv, data) != 0) G_eval_error = EVAL_FUNCTION_ERROR; DB(printf("-- rv = %f\n", rv)); } } } break; case 'n': /* number */ DB(printf("number value '%s'=%f\n", tok.str, tok.value)); rv = tok.value; break; case '(': DB(printf("start grouping\n")); rv = eval_expr(buf, pos); tok = pull_token(buf, pos); if(tok.type != ')') G_eval_error = EVAL_SYNTAX_ERROR; break; default: DB(printf("PUSHBACK\n")); push_token(tok); }
static double eval_term(const char *buf, int *pos) /* term = fact*term | fact/term | fact */ { double rv = 0.0, lhs, rhs; Token tok; DB(printf("-- eval_term(\"%s\", &pos=%p pos=%d)\n", buf+*pos, pos, *pos)); lhs = eval_fact(buf, pos); if(G_eval_error) return rv; DB(printf("-- term lhs=%f\n", lhs)); tok = pull_token(buf, pos); if(G_eval_error) return rv; DB(printf("-- term token type '%c' = ", tok.type)); switch(tok.type) { case '\0': DB(printf("END OF BUFFER\n")); rv = lhs; break; case '*': /* multiplication */ rhs = eval_term(buf, pos); DB(printf("%f*%f", lhs, rhs)); rv = lhs*rhs; DB(printf("=%f\n", rv)); break; case '/': /* division */ rhs = eval_term(buf, pos); DB(printf("%f/%f", lhs, rhs)); if(rhs == 0.0) { DB(printf(" DIVISION BY ZERO\n")); G_eval_error = EVAL_DIVIDE_BY_ZERO; }else { rv = lhs/rhs; DB(printf("=%f\n", rv)); } break; case '\\': /* modulo division */ rhs = eval_term(buf, pos); DB(printf("%f%%%f", lhs, rhs)); if(rhs == 0.0) { DB(printf(" DIVISION BY ZERO\n")); G_eval_error = EVAL_DIVIDE_BY_ZERO; }else { rv = fmod(lhs, rhs); DB(printf("=%f\n", rv)); } break; default: DB(printf("PUSHBACK\n")); push_token(tok); rv = lhs; } DB(printf("-- term rv=%f\n", rv)); return rv; }
DB(printf("number value '%s'=%f\n", tok.str, tok.value)); rv = tok.value; break; case '(': DB(printf("start grouping\n")); rv = eval_expr(buf, pos); tok = pull_token(buf, pos); if(tok.type != ')') G_eval_error = EVAL_SYNTAX_ERROR; break; default: DB(printf("PUSHBACK\n")); push_token(tok); } tok = pull_token(buf, pos); while(tok.type == '%') { rv = rv/100.0; tok = pull_token(buf, pos); } if(tok.type != '\0') push_token(tok); DB(printf("-- item rv=%f\n", rv)); return rv; } static int eval_args(const char *buf, int *pos, int *args, double **arg, int *arglen, int argpos) /* args = expr,args | expr | */ {
/** * Parse the query which has been set up. * \param state Parser state we already setup with QueryParserStart * \return 0 on success, error codes otherwise. */ int QueryParserRun(struct parser_state *state, BOOL strict_quotes) { char *token; struct expression *current_expression = state->start; while (pull_token(&(state->query_ptr), &token) != -1) { if (current_expression < state->start) { // ran off the top of our stack, but there were still tokens DEBUG_MESSAGE("ERR: tokens remaining in data\n"); return -1; } if (QueryParser_IsOp(token) == 0) { if (current_expression->op != NULL) { // check this operator will allow sub-expressions // TODO - this isn't quite right yet. //if (QueryParser_CanSubExp(current_expression->op) == 0) { // DEBUG_MESSAGE("ERR: Cannot accept subexpression at this point\n"); // return -1; //} // need to find a free expr slot struct expression *next_expression = ++(state->last); // check we're not off the end of the array if (state->last > (state->start + state->entries)) { DEBUG_MESSAGE("ERR: ran off end of array\n"); return -1; } // link the current expression to the new one if (current_expression->exp1 == NULL) { current_expression->exp1 = next_expression; } else if (current_expression->exp2 == NULL) { current_expression->exp2 = next_expression; } else { // bad expression with three args or something DEBUG_MESSAGE("ERR: Too many args\n"); return -1; } // advance to the new expression current_expression = next_expression; } current_expression->op = token; } else { // find the next last expression with free slots if (rewind_expression(¤t_expression, state->start)) { DEBUG_MESSAGE("ERR: ran off the start of the array\n"); return -1; } if (current_expression->op == NULL) { // we can't set parameters before we have an operator... DEBUG_MESSAGE("ERR: parameters received before operator\n"); return -1; } int type = 0; if (token[0] == '\'') { // could be a string if (QueryParser_IsString(token) == 0) type = 2; } else if (QueryParser_IsNumber(token) == 0) { // is a number type = 3; } else if (QueryParser_IsProperty(token) == 0) { type = 1; } if ((strict_quotes == TRUE) && (type == 0)) { DEBUG_MESSAGE("ERR: Token not correctly quoted\n"); return -1; } if (current_expression->exp1 == NULL) { current_expression->exp1 = token; current_expression->exp1_const = 1; current_expression->exp1_type = type; } else if (current_expression->exp2 == NULL) { current_expression->exp2 = token; current_expression->exp2_const = 1; current_expression->exp2_type = type; // ignore errors here, since when we fill the last slot // we pop off top of the stack. That's not an error if // there are no more tokens (see check at top of loop) rewind_expression(¤t_expression, state->start); } } } if (current_expression >= state->start) { // we didn't fill all our slots... DEBUG_MESSAGE("ERR: not enough parameters received\n"); return -1; } return 0; }