Missing extern declaration for av_strtod.
[ffmpeg.git] / libavcodec / eval.c
1 /*
2  * simple arithmetic expression evaluator
3  *
4  * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  */
21
22 /**
23  * @file eval.c
24  * simple arithmetic expression evaluator.
25  *
26  * see http://joe.hotchkiss.com/programming/eval/eval.html
27  */
28
29 #include "avcodec.h"
30 #include "mpegvideo.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36
37 #ifndef NAN
38   #define NAN 0.0/0.0
39 #endif
40
41 #ifndef M_PI
42 #define M_PI 3.14159265358979323846
43 #endif
44
45 typedef struct Parser{
46     int stack_index;
47     char *s;
48     double *const_value;
49     const char **const_name;          // NULL terminated
50     double (**func1)(void *, double a); // NULL terminated
51     const char **func1_name;          // NULL terminated
52     double (**func2)(void *, double a, double b); // NULL terminated
53     char **func2_name;          // NULL terminated
54     void *opaque;
55 } Parser;
56
57 extern double av_strtod(const char *name, char **tail);
58
59 static double evalExpression(Parser *p);
60
61 static int strmatch(const char *s, const char *prefix){
62     int i;
63     for(i=0; prefix[i]; i++){
64         if(prefix[i] != s[i]) return 0;
65     }
66     return 1;
67 }
68
69 static double evalPrimary(Parser *p){
70     double d, d2=NAN;
71     char *next= p->s;
72     int i;
73
74     /* number */
75     d= av_strtod(p->s, &next);
76     if(next != p->s){
77         p->s= next;
78         return d;
79     }
80
81     /* named constants */
82     for(i=0; p->const_name && p->const_name[i]; i++){
83         if(strmatch(p->s, p->const_name[i])){
84             p->s+= strlen(p->const_name[i]);
85             return p->const_value[i];
86         }
87     }
88
89     p->s= strchr(p->s, '(');
90     if(p->s==NULL){
91         av_log(NULL, AV_LOG_ERROR, "Parser: missing ( in \"%s\"\n", next);
92         p->s= next;
93         return NAN;
94     }
95     p->s++; // "("
96     d= evalExpression(p);
97     if(p->s[0]== ','){
98         p->s++; // ","
99         d2= evalExpression(p);
100     }
101     if(p->s[0] != ')'){
102         av_log(NULL, AV_LOG_ERROR, "Parser: missing ) in \"%s\"\n", next);
103         return NAN;
104     }
105     p->s++; // ")"
106
107          if( strmatch(next, "sinh"  ) ) d= sinh(d);
108     else if( strmatch(next, "cosh"  ) ) d= cosh(d);
109     else if( strmatch(next, "tanh"  ) ) d= tanh(d);
110     else if( strmatch(next, "sin"   ) ) d= sin(d);
111     else if( strmatch(next, "cos"   ) ) d= cos(d);
112     else if( strmatch(next, "tan"   ) ) d= tan(d);
113     else if( strmatch(next, "exp"   ) ) d= exp(d);
114     else if( strmatch(next, "log"   ) ) d= log(d);
115     else if( strmatch(next, "squish") ) d= 1/(1+exp(4*d));
116     else if( strmatch(next, "gauss" ) ) d= exp(-d*d/2)/sqrt(2*M_PI);
117     else if( strmatch(next, "abs"   ) ) d= fabs(d);
118     else if( strmatch(next, "max"   ) ) d= d >  d2 ?   d : d2;
119     else if( strmatch(next, "min"   ) ) d= d <  d2 ?   d : d2;
120     else if( strmatch(next, "gt"    ) ) d= d >  d2 ? 1.0 : 0.0;
121     else if( strmatch(next, "gte"   ) ) d= d >= d2 ? 1.0 : 0.0;
122     else if( strmatch(next, "lt"    ) ) d= d >  d2 ? 0.0 : 1.0;
123     else if( strmatch(next, "lte"   ) ) d= d >= d2 ? 0.0 : 1.0;
124     else if( strmatch(next, "eq"    ) ) d= d == d2 ? 1.0 : 0.0;
125     else if( strmatch(next, "("     ) ) d= d;
126 //    else if( strmatch(next, "l1"    ) ) d= 1 + d2*(d - 1);
127 //    else if( strmatch(next, "sq01"  ) ) d= (d >= 0.0 && d <=1.0) ? 1.0 : 0.0;
128     else{
129         for(i=0; p->func1_name && p->func1_name[i]; i++){
130             if(strmatch(next, p->func1_name[i])){
131                 return p->func1[i](p->opaque, d);
132             }
133         }
134
135         for(i=0; p->func2_name && p->func2_name[i]; i++){
136             if(strmatch(next, p->func2_name[i])){
137                 return p->func2[i](p->opaque, d, d2);
138             }
139         }
140
141         av_log(NULL, AV_LOG_ERROR, "Parser: unknown function in \"%s\"\n", next);
142         return NAN;
143     }
144
145     return d;
146 }
147
148 static double evalPow(Parser *p){
149     int sign= (*p->s == '+') - (*p->s == '-');
150     p->s += sign&1;
151     return (sign|1) * evalPrimary(p);
152 }
153
154 static double evalFactor(Parser *p){
155     double ret= evalPow(p);
156     while(p->s[0]=='^'){
157         p->s++;
158         ret= pow(ret, evalPow(p));
159     }
160     return ret;
161 }
162
163 static double evalTerm(Parser *p){
164     double ret= evalFactor(p);
165     while(p->s[0]=='*' || p->s[0]=='/'){
166         if(*p->s++ == '*') ret*= evalFactor(p);
167         else               ret/= evalFactor(p);
168     }
169     return ret;
170 }
171
172 static double evalExpression(Parser *p){
173     double ret= 0;
174
175     if(p->stack_index <= 0) //protect against stack overflows
176         return NAN;
177     p->stack_index--;
178
179     do{
180         ret += evalTerm(p);
181     }while(*p->s == '+' || *p->s == '-');
182
183     p->stack_index++;
184
185     return ret;
186 }
187
188 double ff_eval(char *s, double *const_value, const char **const_name,
189                double (**func1)(void *, double), const char **func1_name,
190                double (**func2)(void *, double, double), char **func2_name,
191                void *opaque){
192     Parser p;
193
194     p.stack_index=100;
195     p.s= s;
196     p.const_value= const_value;
197     p.const_name = const_name;
198     p.func1      = func1;
199     p.func1_name = func1_name;
200     p.func2      = func2;
201     p.func2_name = func2_name;
202     p.opaque     = opaque;
203
204     return evalExpression(&p);
205 }
206
207 #ifdef TEST
208 #undef printf
209 static double const_values[]={
210     M_PI,
211     M_E,
212     0
213 };
214 static const char *const_names[]={
215     "PI",
216     "E",
217     0
218 };
219 main(){
220     int i;
221     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));
222     printf("%f == 0.931322575\n", ff_eval("80G/80Gi", const_values, const_names, NULL, NULL, NULL, NULL, NULL));
223
224     for(i=0; i<1050; i++){
225         START_TIMER
226             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);
227         STOP_TIMER("ff_eval")
228     }
229 }
230 #endif