static AVEvalExpr * parse_primary(Parser *p) {
    AVEvalExpr * d = av_mallocz(sizeof(AVEvalExpr));
    char *next= p->s;
    int i;
    d->value = av_strtod(p->s, &next);
    if(next != p->s){
        d->type = e_value;
        p->s= next;
        return d;
    }
    d->value = 1;
    for(i=0; p->const_name && p->const_name[i]; i++){
        if(strmatch(p->s, p->const_name[i])){
            p->s+= strlen(p->const_name[i]);
            d->type = e_const;
            d->a.const_index = i;
            return d;
        }
    }
    p->s= strchr(p->s, '(');
    if(p->s==NULL){
        *p->error = "missing (";
        p->s= next;
        ff_eval_free(d);
        return NULL;
    }
    p->s++;
    if (*next == '(') {
        av_freep(&d);
        d = parse_expr(p);
        if(p->s[0] != ')'){
            *p->error = "missing )";
            ff_eval_free(d);
            return NULL;
        }
        p->s++;
        return d;
    }
    d->param[0] = parse_expr(p);
    if(p->s[0]== ','){
        p->s++;
        d->param[1] = parse_expr(p);
    }
    if(p->s[0] != ')'){
        *p->error = "missing )";
        ff_eval_free(d);
        return NULL;
    }
    p->s++;
    d->type = e_func0;
         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"   ) ) { AVEvalExpr * tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gt; }
    else if( strmatch(next, "lt"    ) ) { AVEvalExpr * 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;
    else if( strmatch(next, "st"    ) ) d->type = e_st;
    else if( strmatch(next, "while" ) ) d->type = e_while;
    else {
        for(i=0; p->func1_name && p->func1_name[i]; i++){
            if(strmatch(next, p->func1_name[i])){
                d->a.func1 = p->func1[i];
                d->type = e_func1;
                return d;
            }
        }
        for(i=0; p->func2_name && p->func2_name[i]; i++){
            if(strmatch(next, p->func2_name[i])){
                d->a.func2 = p->func2[i];
                d->type = e_func2;
                return d;
            }
        }
        *p->error = "unknown function";
        ff_eval_free(d);
        return NULL;
    }
    return d;
}
['const AVOption *av_set_string(void *obj, const char *name, const char *val){\n    const AVOption *o= av_find_opt(obj, name, NULL, 0, 0);\n    if(o && o->offset==0 && o->type == FF_OPT_TYPE_CONST && o->unit){\n        return set_all_opt(obj, o->unit, o->default_val);\n    }\n    if(!o || !val || o->offset<=0)\n        return NULL;\n    if(o->type == FF_OPT_TYPE_BINARY){\n        uint8_t **dst = (uint8_t **)(((uint8_t*)obj) + o->offset);\n        int *lendst = (int *)(dst + 1);\n        uint8_t *bin, *ptr;\n        int len = strlen(val);\n        av_freep(dst);\n        *lendst = 0;\n        if (len & 1) return NULL;\n        len /= 2;\n        ptr = bin = av_malloc(len);\n        while (*val) {\n            int a = hexchar2int(*val++);\n            int b = hexchar2int(*val++);\n            if (a < 0 || b < 0) {\n                av_free(bin);\n                return NULL;\n            }\n            *ptr++ = (a << 4) | b;\n        }\n        *dst = bin;\n        *lendst = len;\n        return o;\n    }\n    if(o->type != FF_OPT_TYPE_STRING){\n        for(;;){\n            int i;\n            char buf[256];\n            int cmd=0;\n            double d;\n            const char *error = NULL;\n            if(*val == \'+\' || *val == \'-\')\n                cmd= *(val++);\n            for(i=0; i<sizeof(buf)-1 && val[i] && val[i]!=\'+\' && val[i]!=\'-\'; i++)\n                buf[i]= val[i];\n            buf[i]=0;\n            val+= i;\n            d = ff_eval2(buf, const_values, const_names, NULL, NULL, NULL, NULL, NULL, &error);\n            if(isnan(d)) {\n                const AVOption *o_named= av_find_opt(obj, buf, o->unit, 0, 0);\n                if(o_named && o_named->type == FF_OPT_TYPE_CONST)\n                    d= o_named->default_val;\n                else if(!strcmp(buf, "default")) d= o->default_val;\n                else if(!strcmp(buf, "max"    )) d= o->max;\n                else if(!strcmp(buf, "min"    )) d= o->min;\n                else if(!strcmp(buf, "none"   )) d= 0;\n                else if(!strcmp(buf, "all"    )) d= ~0;\n                else {\n                    if (!error)\n                        av_log(NULL, AV_LOG_ERROR, "Unable to parse option value \\"%s\\": %s\\n", val, error);\n                    return NULL;\n                }\n            }\n            if(o->type == FF_OPT_TYPE_FLAGS){\n                if     (cmd==\'+\') d= av_get_int(obj, name, NULL) | (int64_t)d;\n                else if(cmd==\'-\') d= av_get_int(obj, name, NULL) &~(int64_t)d;\n            }else if(cmd==\'-\')\n                d= -d;\n            av_set_number(obj, name, d, 1, 1);\n            if(!*val)\n                return o;\n        }\n        return NULL;\n    }\n    memcpy(((uint8_t*)obj) + o->offset, &val, sizeof(val));\n    return o;\n}', 'double ff_eval2(const char *s, double *const_value, const char **const_name,\n               double (**func1)(void *, double), const char **func1_name,\n               double (**func2)(void *, double, double), char **func2_name,\n               void *opaque, const char **error){\n    AVEvalExpr * e = ff_parse(s, const_name, func1, func1_name, func2, func2_name, error);\n    double d;\n    if (!e) return NAN;\n    d = ff_parse_eval(e, const_value, opaque);\n    ff_eval_free(e);\n    return d;\n}', 'AVEvalExpr * ff_parse(const char *s, const char **const_name,\n               double (**func1)(void *, double), const char **func1_name,\n               double (**func2)(void *, double, double), char **func2_name,\n               const char **error){\n    Parser p;\n    AVEvalExpr * e;\n    char w[strlen(s) + 1], * wp = w;\n    while (*s)\n        if (!isspace(*s++)) *wp++ = s[-1];\n    *wp++ = 0;\n    p.stack_index=100;\n    p.s= w;\n    p.const_name = const_name;\n    p.func1      = func1;\n    p.func1_name = func1_name;\n    p.func2      = func2;\n    p.func2_name = func2_name;\n    p.error= error;\n    e = parse_expr(&p);\n    if (!verify_expr(e)) {\n        ff_eval_free(e);\n        return NULL;\n    }\n    return e;\n}', "static AVEvalExpr * parse_expr(Parser *p) {\n    AVEvalExpr * e;\n    if(p->stack_index <= 0)\n        return NULL;\n    p->stack_index--;\n    e = parse_subexpr(p);\n    while(*p->s == ';') {\n        p->s++;\n        e= new_eval_expr(e_last, 1, e, parse_subexpr(p));\n    };\n    p->stack_index++;\n    return e;\n}", "static AVEvalExpr * parse_subexpr(Parser *p) {\n    AVEvalExpr * e = parse_term(p);\n    while(*p->s == '+' || *p->s == '-') {\n        e= new_eval_expr(e_add, 1, e, parse_term(p));\n    };\n    return e;\n}", "static AVEvalExpr * parse_term(Parser *p){\n    AVEvalExpr * e = parse_factor(p);\n    while(p->s[0]=='*' || p->s[0]=='/'){\n        int c= *p->s++;\n        e= new_eval_expr(c == '*' ? e_mul : e_div, 1, e, parse_factor(p));\n    }\n    return e;\n}", "static AVEvalExpr * parse_factor(Parser *p){\n    int sign, sign2;\n    AVEvalExpr * e = parse_pow(p, &sign);\n    while(p->s[0]=='^'){\n        p->s++;\n        e= new_eval_expr(e_pow, 1, e, parse_pow(p, &sign2));\n        if (e->param[1]) e->param[1]->value *= (sign2|1);\n    }\n    if (e) e->value *= (sign|1);\n    return e;\n}", "static AVEvalExpr * parse_pow(Parser *p, int *sign){\n    *sign= (*p->s == '+') - (*p->s == '-');\n    p->s += *sign&1;\n    return parse_primary(p);\n}", 'static AVEvalExpr * parse_primary(Parser *p) {\n    AVEvalExpr * d = av_mallocz(sizeof(AVEvalExpr));\n    char *next= p->s;\n    int i;\n    d->value = av_strtod(p->s, &next);\n    if(next != p->s){\n        d->type = e_value;\n        p->s= next;\n        return d;\n    }\n    d->value = 1;\n    for(i=0; p->const_name && p->const_name[i]; i++){\n        if(strmatch(p->s, p->const_name[i])){\n            p->s+= strlen(p->const_name[i]);\n            d->type = e_const;\n            d->a.const_index = i;\n            return d;\n        }\n    }\n    p->s= strchr(p->s, \'(\');\n    if(p->s==NULL){\n        *p->error = "missing (";\n        p->s= next;\n        ff_eval_free(d);\n        return NULL;\n    }\n    p->s++;\n    if (*next == \'(\') {\n        av_freep(&d);\n        d = parse_expr(p);\n        if(p->s[0] != \')\'){\n            *p->error = "missing )";\n            ff_eval_free(d);\n            return NULL;\n        }\n        p->s++;\n        return d;\n    }\n    d->param[0] = parse_expr(p);\n    if(p->s[0]== \',\'){\n        p->s++;\n        d->param[1] = parse_expr(p);\n    }\n    if(p->s[0] != \')\'){\n        *p->error = "missing )";\n        ff_eval_free(d);\n        return NULL;\n    }\n    p->s++;\n    d->type = e_func0;\n         if( strmatch(next, "sinh"  ) ) d->a.func0 = sinh;\n    else if( strmatch(next, "cosh"  ) ) d->a.func0 = cosh;\n    else if( strmatch(next, "tanh"  ) ) d->a.func0 = tanh;\n    else if( strmatch(next, "sin"   ) ) d->a.func0 = sin;\n    else if( strmatch(next, "cos"   ) ) d->a.func0 = cos;\n    else if( strmatch(next, "tan"   ) ) d->a.func0 = tan;\n    else if( strmatch(next, "atan"  ) ) d->a.func0 = atan;\n    else if( strmatch(next, "asin"  ) ) d->a.func0 = asin;\n    else if( strmatch(next, "acos"  ) ) d->a.func0 = acos;\n    else if( strmatch(next, "exp"   ) ) d->a.func0 = exp;\n    else if( strmatch(next, "log"   ) ) d->a.func0 = log;\n    else if( strmatch(next, "abs"   ) ) d->a.func0 = fabs;\n    else if( strmatch(next, "squish") ) d->type = e_squish;\n    else if( strmatch(next, "gauss" ) ) d->type = e_gauss;\n    else if( strmatch(next, "mod"   ) ) d->type = e_mod;\n    else if( strmatch(next, "max"   ) ) d->type = e_max;\n    else if( strmatch(next, "min"   ) ) d->type = e_min;\n    else if( strmatch(next, "eq"    ) ) d->type = e_eq;\n    else if( strmatch(next, "gte"   ) ) d->type = e_gte;\n    else if( strmatch(next, "gt"    ) ) d->type = e_gt;\n    else if( strmatch(next, "lte"   ) ) { AVEvalExpr * tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gt; }\n    else if( strmatch(next, "lt"    ) ) { AVEvalExpr * tmp = d->param[1]; d->param[1] = d->param[0]; d->param[0] = tmp; d->type = e_gte; }\n    else if( strmatch(next, "ld"    ) ) d->type = e_ld;\n    else if( strmatch(next, "st"    ) ) d->type = e_st;\n    else if( strmatch(next, "while" ) ) d->type = e_while;\n    else {\n        for(i=0; p->func1_name && p->func1_name[i]; i++){\n            if(strmatch(next, p->func1_name[i])){\n                d->a.func1 = p->func1[i];\n                d->type = e_func1;\n                return d;\n            }\n        }\n        for(i=0; p->func2_name && p->func2_name[i]; i++){\n            if(strmatch(next, p->func2_name[i])){\n                d->a.func2 = p->func2[i];\n                d->type = e_func2;\n                return d;\n            }\n        }\n        *p->error = "unknown function";\n        ff_eval_free(d);\n        return NULL;\n    }\n    return d;\n}']