eval.c 19.4 KB
Newer Older
Michael Niedermayer's avatar
Michael Niedermayer committed
1
/*
2
 * Copyright (c) 2002-2006 Michael Niedermayer <michaelni@gmx.at>
3
 * Copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
Michael Niedermayer's avatar
Michael Niedermayer committed
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
Michael Niedermayer's avatar
Michael Niedermayer committed
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
Michael Niedermayer's avatar
Michael Niedermayer committed
11
 *
12
 * Libav is distributed in the hope that it will be useful,
Michael Niedermayer's avatar
Michael Niedermayer committed
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Michael Niedermayer's avatar
Michael Niedermayer committed
20 21
 */

Michael Niedermayer's avatar
Michael Niedermayer committed
22
/**
23
 * @file
Michael Niedermayer's avatar
Michael Niedermayer committed
24 25
 * simple arithmetic expression evaluator.
 *
Michael Niedermayer's avatar
Michael Niedermayer committed
26 27 28
 * see http://joe.hotchkiss.com/programming/eval/eval.html
 */

29
#include "libavutil/avutil.h"
30 31
#include "eval.h"

32
typedef struct Parser {
33
    const AVClass *class;
Michael Niedermayer's avatar
Michael Niedermayer committed
34 35
    int stack_index;
    char *s;
36 37 38 39 40 41
    const double *const_values;
    const char * const *const_names;          // NULL terminated
    double (* const *funcs1)(void *, double a);           // NULL terminated
    const char * const *func1_names;          // NULL terminated
    double (* const *funcs2)(void *, double a, double b); // NULL terminated
    const char * const *func2_names;          // NULL terminated
Michael Niedermayer's avatar
Michael Niedermayer committed
42
    void *opaque;
43 44
    int log_offset;
    void *log_ctx;
45 46
#define VARS 10
    double var[VARS];
Michael Niedermayer's avatar
Michael Niedermayer committed
47 48
} Parser;

49 50
static const AVClass class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) };

51
static const int8_t si_prefixes['z' - 'E' + 1] = {
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    ['y'-'E']= -24,
    ['z'-'E']= -21,
    ['a'-'E']= -18,
    ['f'-'E']= -15,
    ['p'-'E']= -12,
    ['n'-'E']= - 9,
    ['u'-'E']= - 6,
    ['m'-'E']= - 3,
    ['c'-'E']= - 2,
    ['d'-'E']= - 1,
    ['h'-'E']=   2,
    ['k'-'E']=   3,
    ['K'-'E']=   3,
    ['M'-'E']=   6,
    ['G'-'E']=   9,
    ['T'-'E']=  12,
    ['P'-'E']=  15,
    ['E'-'E']=  18,
    ['Z'-'E']=  21,
    ['Y'-'E']=  24,
};

74 75
double av_strtod(const char *numstr, char **tail)
{
76 77
    double d;
    char *next;
78
    d = strtod(numstr, &next);
79
    /* if parsing succeeded, check for and interpret postfixes */
80
    if (next!=numstr) {
81
        if (*next >= 'E' && *next <= 'z') {
82
            int e= si_prefixes[*next - 'E'];
83 84
            if (e) {
                if (next[1] == 'i') {
85 86
                    d*= pow( 2, e/0.3);
                    next+=2;
87
                } else {
88 89 90 91 92 93
                    d*= pow(10, e);
                    next++;
                }
            }
        }

94
        if (*next=='B') {
95
            d*=8;
96
            next++;
97 98 99 100 101 102 103 104 105
        }
    }
    /* if requested, fill in tail with the position after the last parsed
       character */
    if (tail)
        *tail = next;
    return d;
}

106 107
#define IS_IDENTIFIER_CHAR(c) ((c) - '0' <= 9U || (c) - 'a' <= 25U || (c) - 'A' <= 25U || (c) == '_')

108 109
static int strmatch(const char *s, const char *prefix)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
110
    int i;
111 112
    for (i=0; prefix[i]; i++) {
        if (prefix[i] != s[i]) return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
113
    }
114 115
    /* return 1 only if the s identifier is terminated */
    return !IS_IDENTIFIER_CHAR(s[i]);
Michael Niedermayer's avatar
Michael Niedermayer committed
116 117
}

118
struct AVExpr {
119 120
    enum {
        e_value, e_const, e_func0, e_func1, e_func2,
121
        e_squish, e_gauss, e_ld, e_isnan,
122 123
        e_mod, e_max, e_min, e_eq, e_gt, e_gte,
        e_pow, e_mul, e_div, e_add,
124
        e_last, e_st, e_while, e_floor, e_ceil, e_trunc,
125 126 127 128 129 130 131 132
    } type;
    double value; // is sign in other types
    union {
        int const_index;
        double (*func0)(double);
        double (*func1)(void *, double);
        double (*func2)(void *, double, double);
    } a;
133
    struct AVExpr *param[2];
134 135
};

136 137
static double eval_expr(Parser *p, AVExpr *e)
{
138 139
    switch (e->type) {
        case e_value:  return e->value;
140
        case e_const:  return e->value * p->const_values[e->a.const_index];
141 142 143 144 145
        case e_func0:  return e->value * e->a.func0(eval_expr(p, e->param[0]));
        case e_func1:  return e->value * e->a.func1(p->opaque, eval_expr(p, e->param[0]));
        case e_func2:  return e->value * e->a.func2(p->opaque, eval_expr(p, e->param[0]), eval_expr(p, e->param[1]));
        case e_squish: return 1/(1+exp(4*eval_expr(p, e->param[0])));
        case e_gauss: { double d = eval_expr(p, e->param[0]); return exp(-d*d/2)/sqrt(2*M_PI); }
146
        case e_ld:     return e->value * p->var[av_clip(eval_expr(p, e->param[0]), 0, VARS-1)];
147
        case e_isnan:  return e->value * !!isnan(eval_expr(p, e->param[0]));
148 149 150
        case e_floor:  return e->value * floor(eval_expr(p, e->param[0]));
        case e_ceil :  return e->value * ceil (eval_expr(p, e->param[0]));
        case e_trunc:  return e->value * trunc(eval_expr(p, e->param[0]));
151
        case e_while: {
152
            double d = NAN;
153
            while (eval_expr(p, e->param[0]))
154 155 156
                d=eval_expr(p, e->param[1]);
            return d;
        }
157 158 159 160 161 162 163 164 165 166 167 168 169 170
        default: {
            double d = eval_expr(p, e->param[0]);
            double d2 = eval_expr(p, e->param[1]);
            switch (e->type) {
                case e_mod: return e->value * (d - floor(d/d2)*d2);
                case e_max: return e->value * (d >  d2 ?   d : d2);
                case e_min: return e->value * (d <  d2 ?   d : d2);
                case e_eq:  return e->value * (d == d2 ? 1.0 : 0.0);
                case e_gt:  return e->value * (d >  d2 ? 1.0 : 0.0);
                case e_gte: return e->value * (d >= d2 ? 1.0 : 0.0);
                case e_pow: return e->value * pow(d, d2);
                case e_mul: return e->value * (d * d2);
                case e_div: return e->value * (d / d2);
                case e_add: return e->value * (d + d2);
Oded Shimon's avatar
Oded Shimon committed
171
                case e_last:return e->value * d2;
172
                case e_st : return e->value * (p->var[av_clip(d, 0, VARS-1)]= d2);
173 174 175 176 177 178
            }
        }
    }
    return NAN;
}

179
static int parse_expr(AVExpr **e, Parser *p);
180

181
void av_expr_free(AVExpr *e)
182
{
183
    if (!e) return;
184 185
    av_expr_free(e->param[0]);
    av_expr_free(e->param[1]);
186 187 188
    av_freep(&e);
}

189 190
static int parse_primary(AVExpr **e, Parser *p)
{
191
    AVExpr *d = av_mallocz(sizeof(AVExpr));
192
    char *next = p->s, *s0 = p->s;
193
    int ret, i;
Michael Niedermayer's avatar
Michael Niedermayer committed
194

195
    if (!d)
196
        return AVERROR(ENOMEM);
197

Michael Niedermayer's avatar
Michael Niedermayer committed
198
    /* number */
199
    d->value = av_strtod(p->s, &next);
200
    if (next != p->s) {
201
        d->type = e_value;
Michael Niedermayer's avatar
Michael Niedermayer committed
202
        p->s= next;
203 204
        *e = d;
        return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
205
    }
206
    d->value = 1;
207

Michael Niedermayer's avatar
Michael Niedermayer committed
208
    /* named constants */
209 210
    for (i=0; p->const_names && p->const_names[i]; i++) {
        if (strmatch(p->s, p->const_names[i])) {
211
            p->s+= strlen(p->const_names[i]);
212 213
            d->type = e_const;
            d->a.const_index = i;
214 215
            *e = d;
            return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
216 217
        }
    }
218

Michael Niedermayer's avatar
Michael Niedermayer committed
219
    p->s= strchr(p->s, '(');
220
    if (p->s==NULL) {
221
        av_log(p, AV_LOG_ERROR, "Undefined constant or missing '(' in '%s'\n", s0);
Michael Niedermayer's avatar
Michael Niedermayer committed
222
        p->s= next;
223
        av_expr_free(d);
224
        return AVERROR(EINVAL);
Michael Niedermayer's avatar
Michael Niedermayer committed
225 226
    }
    p->s++; // "("
227 228
    if (*next == '(') { // special case do-nothing
        av_freep(&d);
229 230
        if ((ret = parse_expr(&d, p)) < 0)
            return ret;
231
        if (p->s[0] != ')') {
232
            av_log(p, AV_LOG_ERROR, "Missing ')' in '%s'\n", s0);
233
            av_expr_free(d);
234
            return AVERROR(EINVAL);
235 236
        }
        p->s++; // ")"
237 238 239 240
        *e = d;
        return 0;
    }
    if ((ret = parse_expr(&(d->param[0]), p)) < 0) {
241
        av_expr_free(d);
242
        return ret;
243
    }
244
    if (p->s[0]== ',') {
245
        p->s++; // ","
246
        parse_expr(&d->param[1], p);
Michael Niedermayer's avatar
Michael Niedermayer committed
247
    }
248
    if (p->s[0] != ')') {
249
        av_log(p, AV_LOG_ERROR, "Missing ')' or too many args in '%s'\n", s0);
250
        av_expr_free(d);
251
        return AVERROR(EINVAL);
252 253
    }
    p->s++; // ")"
254

255
    d->type = e_func0;
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
         if (strmatch(next, "sinh"  )) d->a.func0 = sinh;
    else if (strmatch(next, "cosh"  )) d->a.func0 = cosh;
    else if (strmatch(next, "tanh"  )) d->a.func0 = tanh;
    else if (strmatch(next, "sin"   )) d->a.func0 = sin;
    else if (strmatch(next, "cos"   )) d->a.func0 = cos;
    else if (strmatch(next, "tan"   )) d->a.func0 = tan;
    else if (strmatch(next, "atan"  )) d->a.func0 = atan;
    else if (strmatch(next, "asin"  )) d->a.func0 = asin;
    else if (strmatch(next, "acos"  )) d->a.func0 = acos;
    else if (strmatch(next, "exp"   )) d->a.func0 = exp;
    else if (strmatch(next, "log"   )) d->a.func0 = log;
    else if (strmatch(next, "abs"   )) d->a.func0 = fabs;
    else if (strmatch(next, "squish")) d->type = e_squish;
    else if (strmatch(next, "gauss" )) d->type = e_gauss;
    else if (strmatch(next, "mod"   )) d->type = e_mod;
    else if (strmatch(next, "max"   )) d->type = e_max;
    else if (strmatch(next, "min"   )) d->type = e_min;
    else if (strmatch(next, "eq"    )) d->type = e_eq;
    else if (strmatch(next, "gte"   )) d->type = e_gte;
    else if (strmatch(next, "gt"    )) d->type = e_gt;
    else if (strmatch(next, "lte"   )) { AVExpr *tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gt; }
    else if (strmatch(next, "lt"    )) { AVExpr *tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gte; }
    else if (strmatch(next, "ld"    )) d->type = e_ld;
279
    else if (strmatch(next, "isnan" )) d->type = e_isnan;
280 281
    else if (strmatch(next, "st"    )) d->type = e_st;
    else if (strmatch(next, "while" )) d->type = e_while;
282 283 284
    else if (strmatch(next, "floor" )) d->type = e_floor;
    else if (strmatch(next, "ceil"  )) d->type = e_ceil;
    else if (strmatch(next, "trunc" )) d->type = e_trunc;
285
    else {
286 287
        for (i=0; p->func1_names && p->func1_names[i]; i++) {
            if (strmatch(next, p->func1_names[i])) {
288
                d->a.func1 = p->funcs1[i];
289
                d->type = e_func1;
290 291
                *e = d;
                return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
292 293 294
            }
        }

295 296
        for (i=0; p->func2_names && p->func2_names[i]; i++) {
            if (strmatch(next, p->func2_names[i])) {
297
                d->a.func2 = p->funcs2[i];
298
                d->type = e_func2;
299 300
                *e = d;
                return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
301 302 303
            }
        }

304
        av_log(p, AV_LOG_ERROR, "Unknown function in '%s'\n", s0);
305
        av_expr_free(d);
306
        return AVERROR(EINVAL);
Michael Niedermayer's avatar
Michael Niedermayer committed
307
    }
308

309 310
    *e = d;
    return 0;
311
}
Michael Niedermayer's avatar
Michael Niedermayer committed
312

313 314 315
static AVExpr *new_eval_expr(int type, int value, AVExpr *p0, AVExpr *p1)
{
    AVExpr *e = av_mallocz(sizeof(AVExpr));
316 317
    if (!e)
        return NULL;
318 319 320 321 322 323 324
    e->type     =type   ;
    e->value    =value  ;
    e->param[0] =p0     ;
    e->param[1] =p1     ;
    return e;
}

325 326
static int parse_pow(AVExpr **e, Parser *p, int *sign)
{
327 328
    *sign= (*p->s == '+') - (*p->s == '-');
    p->s += *sign&1;
329
    return parse_primary(e, p);
Michael Niedermayer's avatar
Michael Niedermayer committed
330 331
}

332 333 334 335 336 337
static int parse_factor(AVExpr **e, Parser *p)
{
    int sign, sign2, ret;
    AVExpr *e0, *e1, *e2;
    if ((ret = parse_pow(&e0, p, &sign)) < 0)
        return ret;
Michael Niedermayer's avatar
Michael Niedermayer committed
338
    while(p->s[0]=='^'){
339
        e1 = e0;
Michael Niedermayer's avatar
Michael Niedermayer committed
340
        p->s++;
341
        if ((ret = parse_pow(&e2, p, &sign2)) < 0) {
342
            av_expr_free(e1);
343 344 345 346
            return ret;
        }
        e0 = new_eval_expr(e_pow, 1, e1, e2);
        if (!e0) {
347 348
            av_expr_free(e1);
            av_expr_free(e2);
349 350 351
            return AVERROR(ENOMEM);
        }
        if (e0->param[1]) e0->param[1]->value *= (sign2|1);
Michael Niedermayer's avatar
Michael Niedermayer committed
352
    }
353 354 355 356
    if (e0) e0->value *= (sign|1);

    *e = e0;
    return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
357 358
}

359 360 361 362 363 364
static int parse_term(AVExpr **e, Parser *p)
{
    int ret;
    AVExpr *e0, *e1, *e2;
    if ((ret = parse_factor(&e0, p)) < 0)
        return ret;
365
    while (p->s[0]=='*' || p->s[0]=='/') {
366
        int c= *p->s++;
367 368
        e1 = e0;
        if ((ret = parse_factor(&e2, p)) < 0) {
369
            av_expr_free(e1);
370 371 372 373
            return ret;
        }
        e0 = new_eval_expr(c == '*' ? e_mul : e_div, 1, e1, e2);
        if (!e0) {
374 375
            av_expr_free(e1);
            av_expr_free(e2);
376 377
            return AVERROR(ENOMEM);
        }
Michael Niedermayer's avatar
Michael Niedermayer committed
378
    }
379 380
    *e = e0;
    return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
381 382
}

383 384 385 386 387 388
static int parse_subexpr(AVExpr **e, Parser *p)
{
    int ret;
    AVExpr *e0, *e1, *e2;
    if ((ret = parse_term(&e0, p)) < 0)
        return ret;
389
    while (*p->s == '+' || *p->s == '-') {
390 391
        e1 = e0;
        if ((ret = parse_term(&e2, p)) < 0) {
392
            av_expr_free(e1);
393 394 395 396
            return ret;
        }
        e0 = new_eval_expr(e_add, 1, e1, e2);
        if (!e0) {
397 398
            av_expr_free(e1);
            av_expr_free(e2);
399 400
            return AVERROR(ENOMEM);
        }
401 402
    };

403 404
    *e = e0;
    return 0;
405 406
}

407 408 409 410
static int parse_expr(AVExpr **e, Parser *p)
{
    int ret;
    AVExpr *e0, *e1, *e2;
411
    if (p->stack_index <= 0) //protect against stack overflows
412
        return AVERROR(EINVAL);
Michael Niedermayer's avatar
Michael Niedermayer committed
413 414
    p->stack_index--;

415 416
    if ((ret = parse_subexpr(&e0, p)) < 0)
        return ret;
417
    while (*p->s == ';') {
418
        p->s++;
419 420
        e1 = e0;
        if ((ret = parse_subexpr(&e2, p)) < 0) {
421
            av_expr_free(e1);
422 423 424 425
            return ret;
        }
        e0 = new_eval_expr(e_last, 1, e1, e2);
        if (!e0) {
426 427
            av_expr_free(e1);
            av_expr_free(e2);
428 429
            return AVERROR(ENOMEM);
        }
430
    };
Michael Niedermayer's avatar
Michael Niedermayer committed
431 432

    p->stack_index++;
433 434
    *e = e0;
    return 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
435 436
}

437 438
static int verify_expr(AVExpr *e)
{
439 440 441 442 443 444 445
    if (!e) return 0;
    switch (e->type) {
        case e_value:
        case e_const: return 1;
        case e_func0:
        case e_func1:
        case e_squish:
446
        case e_ld:
447
        case e_gauss:
448 449 450 451 452
        case e_isnan:
        case e_floor:
        case e_ceil:
        case e_trunc:
            return verify_expr(e->param[0]);
453 454 455 456
        default: return verify_expr(e->param[0]) && verify_expr(e->param[1]);
    }
}

457
int av_expr_parse(AVExpr **expr, const char *s,
458 459 460
                  const char * const *const_names,
                  const char * const *func1_names, double (* const *funcs1)(void *, double),
                  const char * const *func2_names, double (* const *funcs2)(void *, double, double),
461
                  int log_offset, void *log_ctx)
462
{
Michael Niedermayer's avatar
Michael Niedermayer committed
463
    Parser p;
464
    AVExpr *e = NULL;
465 466
    char *w = av_malloc(strlen(s) + 1);
    char *wp = w;
467
    const char *s0 = s;
468
    int ret = 0;
469 470

    if (!w)
471
        return AVERROR(ENOMEM);
Oded Shimon's avatar
Oded Shimon committed
472 473 474 475

    while (*s)
        if (!isspace(*s++)) *wp++ = s[-1];
    *wp++ = 0;
476

477
    p.class      = &class;
Michael Niedermayer's avatar
Michael Niedermayer committed
478
    p.stack_index=100;
Oded Shimon's avatar
Oded Shimon committed
479
    p.s= w;
480 481 482 483 484
    p.const_names = const_names;
    p.funcs1      = funcs1;
    p.func1_names = func1_names;
    p.funcs2      = funcs2;
    p.func2_names = func2_names;
485 486
    p.log_offset = log_offset;
    p.log_ctx    = log_ctx;
487

488 489
    if ((ret = parse_expr(&e, &p)) < 0)
        goto end;
490 491 492 493 494
    if (*p.s) {
        av_log(&p, AV_LOG_ERROR, "Invalid chars '%s' at the end of expression '%s'\n", p.s, s0);
        ret = AVERROR(EINVAL);
        goto end;
    }
495
    if (!verify_expr(e)) {
496
        av_expr_free(e);
497 498
        ret = AVERROR(EINVAL);
        goto end;
499
    }
500
    *expr = e;
501 502
end:
    av_free(w);
503
    return ret;
504 505
}

506
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
507
{
508 509
    Parser p;

510
    p.const_values = const_values;
511 512 513 514
    p.opaque     = opaque;
    return eval_expr(&p, e);
}

515
int av_expr_parse_and_eval(double *d, const char *s,
516 517 518
                           const char * const *const_names, const double *const_values,
                           const char * const *func1_names, double (* const *funcs1)(void *, double),
                           const char * const *func2_names, double (* const *funcs2)(void *, double, double),
519
                           void *opaque, int log_offset, void *log_ctx)
520
{
521
    AVExpr *e = NULL;
522
    int ret = av_expr_parse(&e, s, const_names, func1_names, funcs1, func2_names, funcs2, log_offset, log_ctx);
523 524 525 526 527

    if (ret < 0) {
        *d = NAN;
        return ret;
    }
528 529
    *d = av_expr_eval(e, const_values, opaque);
    av_expr_free(e);
530
    return isnan(*d) ? AVERROR(EINVAL) : 0;
Michael Niedermayer's avatar
Michael Niedermayer committed
531
}
532

533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
#if FF_API_OLD_EVAL_NAMES
int av_parse_expr(AVExpr **expr, const char *s,
                  const char * const *const_names,
                  const char * const *func1_names, double (* const *funcs1)(void *, double),
                  const char * const *func2_names, double (* const *funcs2)(void *, double, double),
                  int log_offset, void *log_ctx)
{
    return av_expr_parse(expr, s, const_names, func1_names, funcs1, func2_names, funcs2,
                      log_offset, log_ctx);
}

double av_eval_expr(AVExpr *e, const double *const_values, void *opaque)
{
    return av_expr_eval(e, const_values, opaque);
}

int av_parse_and_eval_expr(double *res, const char *s,
                           const char * const *const_names, const double *const_values,
                           const char * const *func1_names, double (* const *funcs1)(void *, double),
                           const char * const *func2_names, double (* const *funcs2)(void *, double, double),
                           void *opaque, int log_offset, void *log_ctx)
{
    return av_expr_parse_and_eval(res, s, const_names, const_values, func1_names, funcs1, func2_names, funcs2,
                                  opaque, log_offset, log_ctx);
}

void av_free_expr(AVExpr *e)
{
    av_expr_free(e);
}
#endif /* FF_API_OLD_EVAL_NAMES */

565
#ifdef TEST
566
#undef printf
567
static double const_values[] = {
568 569 570 571
    M_PI,
    M_E,
    0
};
572

573
static const char *const_names[] = {
574 575 576 577
    "PI",
    "E",
    0
};
578

579 580
int main(void)
{
Michael Niedermayer's avatar
Michael Niedermayer committed
581
    int i;
582
    double d;
583 584
    const char **expr, *exprs[] = {
        "",
585
        "1;2",
586 587 588
        "-20",
        "-PI",
        "+PI",
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
        "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)",
        "80G/80Gi"
        "1k",
        "1Gi",
        "1gi",
        "1GiFoo",
        "1k+1k",
        "1Gi*3foo",
        "foo",
        "foo(",
        "foo()",
        "foo)",
        "sin",
        "sin(",
        "sin()",
        "sin)",
        "sin 10",
        "sin(1,2,3)",
        "sin(1 )",
        "1",
        "1foo",
        "bar + PI + E + 100f*2 + foo",
        "13k + 12f - foo(1, 2)",
        "1gi",
        "1Gi",
614 615 616 617 618 619 620 621
        "st(0, 123)",
        "st(1, 123); ld(1)",
        /* compute 1+2+...+N */
        "st(0, 1); while(lte(ld(0), 100), st(1, ld(1)+ld(0));st(0, ld(0)+1)); ld(1)",
        /* compute Fib(N) */
        "st(1, 1); st(2, 2); st(0, 1); while(lte(ld(0),10), st(3, ld(1)+ld(2)); st(1, ld(2)); st(2, ld(3)); st(0, ld(0)+1)); ld(3)",
        "while(0, 10)",
        "st(0, 1); while(lte(ld(0),100), st(1, ld(1)+ld(0)); st(0, ld(0)+1))",
622 623
        "isnan(1)",
        "isnan(NAN)",
624 625 626 627 628 629 630
        "floor(NAN)",
        "floor(123.123)",
        "floor(-123.123)",
        "trunc(123.123)",
        "trunc(-123.123)",
        "ceil(123.123)",
        "ceil(-123.123)",
631 632 633 634 635
        NULL
    };

    for (expr = exprs; *expr; expr++) {
        printf("Evaluating '%s'\n", *expr);
636
        av_expr_parse_and_eval(&d, *expr,
637 638 639 640 641
                               const_names, const_values,
                               NULL, NULL, NULL, NULL, NULL, 0, NULL);
        printf("'%s' -> %f\n\n", *expr, d);
    }

642
    av_expr_parse_and_eval(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)",
643 644
                           const_names, const_values,
                           NULL, NULL, NULL, NULL, NULL, 0, NULL);
645
    printf("%f == 12.7\n", d);
646
    av_expr_parse_and_eval(&d, "80G/80Gi",
647
                           const_names, const_values,
Stefano Sabatini's avatar
Stefano Sabatini committed
648
                           NULL, NULL, NULL, NULL, NULL, 0, NULL);
649
    printf("%f == 0.931322575\n", d);
650

651
    for (i=0; i<1050; i++) {
Michael Niedermayer's avatar
Michael Niedermayer committed
652
        START_TIMER
653
            av_expr_parse_and_eval(&d, "1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)",
654 655
                                   const_names, const_values,
                                   NULL, NULL, NULL, NULL, NULL, 0, NULL);
656
        STOP_TIMER("av_expr_parse_and_eval")
Michael Niedermayer's avatar
Michael Niedermayer committed
657
    }
Diego Biurrun's avatar
Diego Biurrun committed
658
    return 0;
659 660
}
#endif