/* 1 3 val=feval(\\"type\\",cr,x), evaluate parameterized function */ // Data defined for all feval callbacks // #define FEVAL_START i[0] // initialized to 1, set to 0 on first callback call #define FEVAL_X d[0] // input x value #define FEVAL_R d[1] // result value, initialized to 0 static void rf_feval_poly_callback( Data *d) { if( d->FEVAL_START) { d->FEVAL_START = 0; d->FEVAL_R = eval_cell( d->cp, &d->c); } else // using Horner's rule { d->FEVAL_R = eval_cell( d->cp, &d->c) + d->FEVAL_X*d->FEVAL_R; } } static struct feval_callback { const char *type; Traverse_Callback tc; int direction; } feval_callbacks[] = { { "poly", rf_feval_poly_callback, -1 }, //*** // add other function types and callbacks here... //*** { 0, 0, 0 }, }; double rf_feval(const Node *n, const Cell *c) { Data d; struct feval_callback *cb; Traverse_Callback tc = NULL; Node *type = Right(n); Node *cr = type->next; Node *x = cr->next; if( type->type != STRING) { fprintf( out, "feval: first argument must be a string\n"); return 0; } for( cb = feval_callbacks; cb->type; ++cb) if( strcmp( cb->type, type->u.str) == 0) { tc = cb->tc; break; } if( tc == NULL) { fprintf( out, "feval: unknown function type \"%s\"\n", type->u.str); return 0; } if( check_range( cr, "feval: second argument")) return 0; if( x->type == RANGE) { fprintf( out, "feval: third argument can not be a range\n"); return 0; } d.FEVAL_START = 1; d.FEVAL_X = eval_tree( x, c); d.FEVAL_R = 0; ss_traverse_range_adjust( cr, c, tc, &d, cb->direction); return d.FEVAL_R; }