2 * simple arithmetic expression evaluator
4 * Copyright (c) 2002-2006 Michael Niedermayer <michaelni@gmx.at>
5 * Copyright (c) 2006 Oded Shimon <ods15@ods15.dyndns.org>
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 * simple arithmetic expression evaluator.
28 * see http://joe.hotchkiss.com/programming/eval/eval.html
44 #define M_PI 3.14159265358979323846
47 typedef struct Parser
{
51 const char **const_name
; // NULL terminated
52 double (**func1
)(void *, double a
); // NULL terminated
53 const char **func1_name
; // NULL terminated
54 double (**func2
)(void *, double a
, double b
); // NULL terminated
55 char **func2_name
; // NULL terminated
62 static const int8_t si_prefixes
['z' - 'E' + 1]={
85 /** strtod() function extended with 'k', 'M', 'G', 'ki', 'Mi', 'Gi' and 'B'
86 * postfixes. This allows using f.e. kB, MiB, G and B as a postfix. This
87 * function assumes that the unit of numbers is bits not bytes.
89 static double av_strtod(const char *name
, char **tail
) {
92 d
= strtod(name
, &next
);
93 /* if parsing succeeded, check for and interpret postfixes */
96 if(*next
>= 'E' && *next
<= 'z'){
97 int e
= si_prefixes
[*next
- 'E'];
114 /* if requested, fill in tail with the position after the last parsed
121 static int strmatch(const char *s
, const char *prefix
){
123 for(i
=0; prefix
[i
]; i
++){
124 if(prefix
[i
] != s
[i
]) return 0;
131 e_value
, e_const
, e_func0
, e_func1
, e_func2
,
132 e_squish
, e_gauss
, e_ld
,
133 e_mod
, e_max
, e_min
, e_eq
, e_gt
, e_gte
,
134 e_pow
, e_mul
, e_div
, e_add
,
135 e_last
, e_st
, e_while
,
137 double value
; // is sign in other types
140 double (*func0
)(double);
141 double (*func1
)(void *, double);
142 double (*func2
)(void *, double, double);
144 AVEvalExpr
* param
[2];
147 static double eval_expr(Parser
* p
, AVEvalExpr
* e
) {
149 case e_value
: return e
->value
;
150 case e_const
: return e
->value
* p
->const_value
[e
->a
.const_index
];
151 case e_func0
: return e
->value
* e
->a
.func0(eval_expr(p
, e
->param
[0]));
152 case e_func1
: return e
->value
* e
->a
.func1(p
->opaque
, eval_expr(p
, e
->param
[0]));
153 case e_func2
: return e
->value
* e
->a
.func2(p
->opaque
, eval_expr(p
, e
->param
[0]), eval_expr(p
, e
->param
[1]));
154 case e_squish
: return 1/(1+exp(4*eval_expr(p
, e
->param
[0])));
155 case e_gauss
: { double d
= eval_expr(p
, e
->param
[0]); return exp(-d
*d
/2)/sqrt(2*M_PI
); }
156 case e_ld
: return e
->value
* p
->var
[av_clip(eval_expr(p
, e
->param
[0]), 0, VARS
-1)];
159 while(eval_expr(p
, e
->param
[0]))
160 d
=eval_expr(p
, e
->param
[1]);
164 double d
= eval_expr(p
, e
->param
[0]);
165 double d2
= eval_expr(p
, e
->param
[1]);
167 case e_mod
: return e
->value
* (d
- floor(d
/d2
)*d2
);
168 case e_max
: return e
->value
* (d
> d2
? d
: d2
);
169 case e_min
: return e
->value
* (d
< d2
? d
: d2
);
170 case e_eq
: return e
->value
* (d
== d2
? 1.0 : 0.0);
171 case e_gt
: return e
->value
* (d
> d2
? 1.0 : 0.0);
172 case e_gte
: return e
->value
* (d
>= d2
? 1.0 : 0.0);
173 case e_pow
: return e
->value
* pow(d
, d2
);
174 case e_mul
: return e
->value
* (d
* d2
);
175 case e_div
: return e
->value
* (d
/ d2
);
176 case e_add
: return e
->value
* (d
+ d2
);
177 case e_last
:return e
->value
* d2
;
178 case e_st
: return e
->value
* (p
->var
[av_clip(d
, 0, VARS
-1)]= d2
);
185 static AVEvalExpr
* parse_expr(Parser
*p
);
187 void ff_eval_free(AVEvalExpr
* e
) {
189 ff_eval_free(e
->param
[0]);
190 ff_eval_free(e
->param
[1]);
194 static AVEvalExpr
* parse_primary(Parser
*p
) {
195 AVEvalExpr
* d
= av_mallocz(sizeof(AVEvalExpr
));
200 d
->value
= av_strtod(p
->s
, &next
);
208 /* named constants */
209 for(i
=0; p
->const_name
&& p
->const_name
[i
]; i
++){
210 if(strmatch(p
->s
, p
->const_name
[i
])){
211 p
->s
+= strlen(p
->const_name
[i
]);
213 d
->a
.const_index
= i
;
218 p
->s
= strchr(p
->s
, '(');
220 *p
->error
= "undefined constant or missing (";
226 if (*next
== '(') { // special case do-nothing
230 *p
->error
= "missing )";
237 d
->param
[0] = parse_expr(p
);
240 d
->param
[1] = parse_expr(p
);
243 *p
->error
= "missing )";
250 if( strmatch(next
, "sinh" ) ) d
->a
.func0
= sinh
;
251 else if( strmatch(next
, "cosh" ) ) d
->a
.func0
= cosh
;
252 else if( strmatch(next
, "tanh" ) ) d
->a
.func0
= tanh
;
253 else if( strmatch(next
, "sin" ) ) d
->a
.func0
= sin
;
254 else if( strmatch(next
, "cos" ) ) d
->a
.func0
= cos
;
255 else if( strmatch(next
, "tan" ) ) d
->a
.func0
= tan
;
256 else if( strmatch(next
, "atan" ) ) d
->a
.func0
= atan
;
257 else if( strmatch(next
, "asin" ) ) d
->a
.func0
= asin
;
258 else if( strmatch(next
, "acos" ) ) d
->a
.func0
= acos
;
259 else if( strmatch(next
, "exp" ) ) d
->a
.func0
= exp
;
260 else if( strmatch(next
, "log" ) ) d
->a
.func0
= log
;
261 else if( strmatch(next
, "abs" ) ) d
->a
.func0
= fabs
;
262 else if( strmatch(next
, "squish") ) d
->type
= e_squish
;
263 else if( strmatch(next
, "gauss" ) ) d
->type
= e_gauss
;
264 else if( strmatch(next
, "mod" ) ) d
->type
= e_mod
;
265 else if( strmatch(next
, "max" ) ) d
->type
= e_max
;
266 else if( strmatch(next
, "min" ) ) d
->type
= e_min
;
267 else if( strmatch(next
, "eq" ) ) d
->type
= e_eq
;
268 else if( strmatch(next
, "gte" ) ) d
->type
= e_gte
;
269 else if( strmatch(next
, "gt" ) ) d
->type
= e_gt
;
270 else if( strmatch(next
, "lte" ) ) { AVEvalExpr
* tmp
= d
->param
[1]; d
->param
[1] = d
->param
[0]; d
->param
[0] = tmp
; d
->type
= e_gt
; }
271 else if( strmatch(next
, "lt" ) ) { AVEvalExpr
* tmp
= d
->param
[1]; d
->param
[1] = d
->param
[0]; d
->param
[0] = tmp
; d
->type
= e_gte
; }
272 else if( strmatch(next
, "ld" ) ) d
->type
= e_ld
;
273 else if( strmatch(next
, "st" ) ) d
->type
= e_st
;
274 else if( strmatch(next
, "while" ) ) d
->type
= e_while
;
276 for(i
=0; p
->func1_name
&& p
->func1_name
[i
]; i
++){
277 if(strmatch(next
, p
->func1_name
[i
])){
278 d
->a
.func1
= p
->func1
[i
];
284 for(i
=0; p
->func2_name
&& p
->func2_name
[i
]; i
++){
285 if(strmatch(next
, p
->func2_name
[i
])){
286 d
->a
.func2
= p
->func2
[i
];
292 *p
->error
= "unknown function";
300 static AVEvalExpr
* new_eval_expr(int type
, int value
, AVEvalExpr
*p0
, AVEvalExpr
*p1
){
301 AVEvalExpr
* e
= av_mallocz(sizeof(AVEvalExpr
));
309 static AVEvalExpr
* parse_pow(Parser
*p
, int *sign
){
310 *sign
= (*p
->s
== '+') - (*p
->s
== '-');
312 return parse_primary(p
);
315 static AVEvalExpr
* parse_factor(Parser
*p
){
317 AVEvalExpr
* e
= parse_pow(p
, &sign
);
320 e
= new_eval_expr(e_pow
, 1, e
, parse_pow(p
, &sign2
));
321 if (e
->param
[1]) e
->param
[1]->value
*= (sign2
|1);
323 if (e
) e
->value
*= (sign
|1);
327 static AVEvalExpr
* parse_term(Parser
*p
){
328 AVEvalExpr
* e
= parse_factor(p
);
329 while(p
->s
[0]=='*' || p
->s
[0]=='/'){
331 e
= new_eval_expr(c
== '*' ? e_mul
: e_div
, 1, e
, parse_factor(p
));
336 static AVEvalExpr
* parse_subexpr(Parser
*p
) {
337 AVEvalExpr
* e
= parse_term(p
);
338 while(*p
->s
== '+' || *p
->s
== '-') {
339 e
= new_eval_expr(e_add
, 1, e
, parse_term(p
));
345 static AVEvalExpr
* parse_expr(Parser
*p
) {
348 if(p
->stack_index
<= 0) //protect against stack overflows
352 e
= parse_subexpr(p
);
354 while(*p
->s
== ';') {
356 e
= new_eval_expr(e_last
, 1, e
, parse_subexpr(p
));
364 static int verify_expr(AVEvalExpr
* e
) {
368 case e_const
: return 1;
373 case e_gauss
: return verify_expr(e
->param
[0]);
374 default: return verify_expr(e
->param
[0]) && verify_expr(e
->param
[1]);
378 AVEvalExpr
* ff_parse(const char *s
, const char **const_name
,
379 double (**func1
)(void *, double), const char **func1_name
,
380 double (**func2
)(void *, double, double), char **func2_name
,
384 char w
[strlen(s
) + 1], * wp
= w
;
387 if (!isspace(*s
++)) *wp
++ = s
[-1];
392 p
.const_name
= const_name
;
394 p
.func1_name
= func1_name
;
396 p
.func2_name
= func2_name
;
400 if (!verify_expr(e
)) {
407 double ff_parse_eval(AVEvalExpr
* e
, double *const_value
, void *opaque
) {
410 p
.const_value
= const_value
;
412 return eval_expr(&p
, e
);
415 double ff_eval2(const char *s
, double *const_value
, const char **const_name
,
416 double (**func1
)(void *, double), const char **func1_name
,
417 double (**func2
)(void *, double, double), char **func2_name
,
418 void *opaque
, const char **error
){
419 AVEvalExpr
* e
= ff_parse(s
, const_name
, func1
, func1_name
, func2
, func2_name
, error
);
422 d
= ff_parse_eval(e
, const_value
, opaque
);
429 static double const_values
[]={
434 static const char *const_names
[]={
441 printf("%f == 12.7\n", ff_eval("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_values
, const_names
, NULL
, NULL
, NULL
, NULL
, NULL
));
442 printf("%f == 0.931322575\n", ff_eval("80G/80Gi", const_values
, const_names
, NULL
, NULL
, NULL
, NULL
, NULL
));
444 for(i
=0; i
<1050; i
++){
446 ff_eval("1+(5-2)^(3-1)+1/2+sin(PI)-max(-2.2,-3.1)", const_values
, const_names
, NULL
, NULL
, NULL
, NULL
, NULL
);
447 STOP_TIMER("ff_eval")